Merge "Support ignoring app orientation request per display"
diff --git a/apct-tests/perftests/windowmanager/src/android/wm/RelayoutPerfTest.java b/apct-tests/perftests/windowmanager/src/android/wm/RelayoutPerfTest.java
index ecd1499..1be68f5 100644
--- a/apct-tests/perftests/windowmanager/src/android/wm/RelayoutPerfTest.java
+++ b/apct-tests/perftests/windowmanager/src/android/wm/RelayoutPerfTest.java
@@ -135,7 +135,6 @@
final int mHeight;
final Point mOutSurfaceSize = new Point();
final SurfaceControl mOutSurfaceControl;
- final SurfaceControl mOutBlastSurfaceControl = new SurfaceControl();
final IntSupplier mViewVisibility;
@@ -158,7 +157,7 @@
session.relayout(mWindow, mParams, mWidth, mHeight,
mViewVisibility.getAsInt(), mFlags, mFrameNumber, mOutFrames,
mOutMergedConfiguration, mOutSurfaceControl, mOutInsetsState, mOutControls,
- mOutSurfaceSize, mOutBlastSurfaceControl);
+ mOutSurfaceSize);
}
}
}
diff --git a/apex/jobscheduler/service/java/com/android/server/DeviceIdleController.java b/apex/jobscheduler/service/java/com/android/server/DeviceIdleController.java
index 1a81587..81f22fe 100644
--- a/apex/jobscheduler/service/java/com/android/server/DeviceIdleController.java
+++ b/apex/jobscheduler/service/java/com/android/server/DeviceIdleController.java
@@ -2179,7 +2179,7 @@
if (getContext().getResources().getBoolean(
com.android.internal.R.bool.config_autoPowerModePrefetchLocation)) {
mLocationRequest = new LocationRequest.Builder(/*intervalMillis=*/ 0)
- .setQuality(LocationRequest.ACCURACY_FINE)
+ .setQuality(LocationRequest.QUALITY_HIGH_ACCURACY)
.setMaxUpdates(1)
.build();
}
diff --git a/api/current.txt b/api/current.txt
index e2adbc4..b1f6c06 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -2889,6 +2889,7 @@
field public static final int GESTURE_2_FINGER_DOUBLE_TAP = 20; // 0x14
field public static final int GESTURE_2_FINGER_DOUBLE_TAP_AND_HOLD = 40; // 0x28
field public static final int GESTURE_2_FINGER_SINGLE_TAP = 19; // 0x13
+ field public static final int GESTURE_2_FINGER_SINGLE_TAP_AND_HOLD = 43; // 0x2b
field public static final int GESTURE_2_FINGER_SWIPE_DOWN = 26; // 0x1a
field public static final int GESTURE_2_FINGER_SWIPE_LEFT = 27; // 0x1b
field public static final int GESTURE_2_FINGER_SWIPE_RIGHT = 28; // 0x1c
@@ -2897,11 +2898,13 @@
field public static final int GESTURE_3_FINGER_DOUBLE_TAP = 23; // 0x17
field public static final int GESTURE_3_FINGER_DOUBLE_TAP_AND_HOLD = 41; // 0x29
field public static final int GESTURE_3_FINGER_SINGLE_TAP = 22; // 0x16
+ field public static final int GESTURE_3_FINGER_SINGLE_TAP_AND_HOLD = 44; // 0x2c
field public static final int GESTURE_3_FINGER_SWIPE_DOWN = 30; // 0x1e
field public static final int GESTURE_3_FINGER_SWIPE_LEFT = 31; // 0x1f
field public static final int GESTURE_3_FINGER_SWIPE_RIGHT = 32; // 0x20
field public static final int GESTURE_3_FINGER_SWIPE_UP = 29; // 0x1d
field public static final int GESTURE_3_FINGER_TRIPLE_TAP = 24; // 0x18
+ field public static final int GESTURE_3_FINGER_TRIPLE_TAP_AND_HOLD = 45; // 0x2d
field public static final int GESTURE_4_FINGER_DOUBLE_TAP = 38; // 0x26
field public static final int GESTURE_4_FINGER_DOUBLE_TAP_AND_HOLD = 42; // 0x2a
field public static final int GESTURE_4_FINGER_SINGLE_TAP = 37; // 0x25
@@ -10664,12 +10667,15 @@
field public static final String ACTION_PACKAGE_CHANGED = "android.intent.action.PACKAGE_CHANGED";
field public static final String ACTION_PACKAGE_DATA_CLEARED = "android.intent.action.PACKAGE_DATA_CLEARED";
field public static final String ACTION_PACKAGE_FIRST_LAUNCH = "android.intent.action.PACKAGE_FIRST_LAUNCH";
+ field public static final String ACTION_PACKAGE_FULLY_LOADED = "android.intent.action.PACKAGE_FULLY_LOADED";
field public static final String ACTION_PACKAGE_FULLY_REMOVED = "android.intent.action.PACKAGE_FULLY_REMOVED";
field @Deprecated public static final String ACTION_PACKAGE_INSTALL = "android.intent.action.PACKAGE_INSTALL";
field public static final String ACTION_PACKAGE_NEEDS_VERIFICATION = "android.intent.action.PACKAGE_NEEDS_VERIFICATION";
field public static final String ACTION_PACKAGE_REMOVED = "android.intent.action.PACKAGE_REMOVED";
field public static final String ACTION_PACKAGE_REPLACED = "android.intent.action.PACKAGE_REPLACED";
field public static final String ACTION_PACKAGE_RESTARTED = "android.intent.action.PACKAGE_RESTARTED";
+ field public static final String ACTION_PACKAGE_STARTABLE = "android.intent.action.PACKAGE_STARTABLE";
+ field public static final String ACTION_PACKAGE_UNSTARTABLE = "android.intent.action.PACKAGE_UNSTARTABLE";
field public static final String ACTION_PACKAGE_VERIFIED = "android.intent.action.PACKAGE_VERIFIED";
field public static final String ACTION_PASTE = "android.intent.action.PASTE";
field public static final String ACTION_PICK = "android.intent.action.PICK";
@@ -10834,6 +10840,7 @@
field public static final String EXTRA_TIMEZONE = "time-zone";
field public static final String EXTRA_TITLE = "android.intent.extra.TITLE";
field public static final String EXTRA_UID = "android.intent.extra.UID";
+ field public static final String EXTRA_UNSTARTABLE_REASON = "android.intent.extra.UNSTARTABLE_REASON";
field public static final String EXTRA_USER = "android.intent.extra.USER";
field public static final int FILL_IN_ACTION = 1; // 0x1
field public static final int FILL_IN_CATEGORIES = 4; // 0x4
@@ -12293,6 +12300,9 @@
field public static final int SYNCHRONOUS = 2; // 0x2
field @Nullable public static final java.util.List<java.security.cert.Certificate> TRUST_ALL;
field @NonNull public static final java.util.List<java.security.cert.Certificate> TRUST_NONE;
+ field public static final int UNSTARTABLE_REASON_CONNECTION_ERROR = 1; // 0x1
+ field public static final int UNSTARTABLE_REASON_INSUFFICIENT_STORAGE = 2; // 0x2
+ field public static final int UNSTARTABLE_REASON_UNKNOWN = 0; // 0x0
field public static final int VERIFICATION_ALLOW = 1; // 0x1
field public static final int VERIFICATION_REJECT = -1; // 0xffffffff
field public static final int VERSION_CODE_HIGHEST = -1; // 0xffffffff
@@ -24089,9 +24099,13 @@
method @IntRange(from=1, to=java.lang.Integer.MAX_VALUE) public int getMaxUpdates();
method @FloatRange(from=0, to=java.lang.Float.MAX_VALUE) public float getMinUpdateDistanceMeters();
method @IntRange(from=0) public long getMinUpdateIntervalMillis();
+ method public int getQuality();
method public void writeToParcel(@NonNull android.os.Parcel, int);
field @NonNull public static final android.os.Parcelable.Creator<android.location.LocationRequest> CREATOR;
field public static final long PASSIVE_INTERVAL = 9223372036854775807L; // 0x7fffffffffffffffL
+ field public static final int QUALITY_BALANCED_POWER_ACCURACY = 102; // 0x66
+ field public static final int QUALITY_HIGH_ACCURACY = 100; // 0x64
+ field public static final int QUALITY_LOW_POWER = 104; // 0x68
}
public static final class LocationRequest.Builder {
@@ -24104,6 +24118,7 @@
method @NonNull public android.location.LocationRequest.Builder setMaxUpdates(@IntRange(from=1, to=java.lang.Integer.MAX_VALUE) int);
method @NonNull public android.location.LocationRequest.Builder setMinUpdateDistanceMeters(@FloatRange(from=0, to=java.lang.Float.MAX_VALUE) float);
method @NonNull public android.location.LocationRequest.Builder setMinUpdateIntervalMillis(@IntRange(from=0) long);
+ method @NonNull public android.location.LocationRequest.Builder setQuality(int);
}
public interface OnNmeaMessageListener {
diff --git a/api/module-lib-current.txt b/api/module-lib-current.txt
index dc92b52..e825b62 100644
--- a/api/module-lib-current.txt
+++ b/api/module-lib-current.txt
@@ -1,10 +1,20 @@
// Signature format: 2.0
package android.app {
+ public class ActivityManager {
+ method @RequiresPermission(android.Manifest.permission.SET_ACTIVITY_WATCHER) public void addHomeVisibilityListener(@NonNull java.util.concurrent.Executor, @NonNull android.app.HomeVisibilityListener);
+ method @RequiresPermission(android.Manifest.permission.SET_ACTIVITY_WATCHER) public void removeHomeVisibilityListener(@NonNull android.app.HomeVisibilityListener);
+ }
+
public class AppOpsManager {
field public static final String OPSTR_NO_ISOLATED_STORAGE = "android:no_isolated_storage";
}
+ public abstract class HomeVisibilityListener {
+ ctor public HomeVisibilityListener();
+ method public abstract void onHomeVisibilityChanged(boolean);
+ }
+
public class NotificationManager {
method public boolean hasEnabledNotificationListener(@NonNull String, @NonNull android.os.UserHandle);
field public static final String ACTION_NOTIFICATION_LISTENER_ENABLED_CHANGED = "android.app.action.NOTIFICATION_LISTENER_ENABLED_CHANGED";
@@ -178,6 +188,18 @@
}
+package android.telephony {
+
+ public abstract class CellSignalStrength {
+ method public static int getNumSignalStrengthLevels();
+ }
+
+ public class TelephonyManager {
+ method @NonNull public static int[] getAllNetworkTypes();
+ }
+
+}
+
package android.util {
public class AtomicFile {
diff --git a/api/system-current.txt b/api/system-current.txt
index 2e53058..b6b6e5b 100644
--- a/api/system-current.txt
+++ b/api/system-current.txt
@@ -122,6 +122,7 @@
field public static final String MANAGE_FACTORY_RESET_PROTECTION = "android.permission.MANAGE_FACTORY_RESET_PROTECTION";
field public static final String MANAGE_IPSEC_TUNNELS = "android.permission.MANAGE_IPSEC_TUNNELS";
field public static final String MANAGE_MUSIC_RECOGNITION = "android.permission.MANAGE_MUSIC_RECOGNITION";
+ field public static final String MANAGE_NOTIFICATION_LISTENERS = "android.permission.MANAGE_NOTIFICATION_LISTENERS";
field public static final String MANAGE_ONE_TIME_PERMISSION_SESSIONS = "android.permission.MANAGE_ONE_TIME_PERMISSION_SESSIONS";
field public static final String MANAGE_ROLE_HOLDERS = "android.permission.MANAGE_ROLE_HOLDERS";
field public static final String MANAGE_ROLLBACKS = "android.permission.MANAGE_ROLLBACKS";
@@ -674,8 +675,10 @@
public class NotificationManager {
method @NonNull public java.util.List<java.lang.String> getAllowedAssistantAdjustments();
method @Nullable public android.content.ComponentName getAllowedNotificationAssistant();
+ method @NonNull @RequiresPermission(android.Manifest.permission.MANAGE_NOTIFICATION_LISTENERS) public java.util.List<android.content.ComponentName> getEnabledNotificationListeners();
method public boolean isNotificationAssistantAccessGranted(@NonNull android.content.ComponentName);
method public void setNotificationAssistantAccessGranted(@Nullable android.content.ComponentName, boolean);
+ method @RequiresPermission(android.Manifest.permission.MANAGE_NOTIFICATION_LISTENERS) public void setNotificationListenerAccessGranted(@NonNull android.content.ComponentName, boolean);
field @RequiresPermission(android.Manifest.permission.STATUS_BAR_SERVICE) public static final String ACTION_CLOSE_NOTIFICATION_HANDLER_PANEL = "android.app.action.CLOSE_NOTIFICATION_HANDLER_PANEL";
field @RequiresPermission(android.Manifest.permission.STATUS_BAR_SERVICE) public static final String ACTION_OPEN_NOTIFICATION_HANDLER_PANEL = "android.app.action.OPEN_NOTIFICATION_HANDLER_PANEL";
field @RequiresPermission(android.Manifest.permission.STATUS_BAR_SERVICE) public static final String ACTION_TOGGLE_NOTIFICATION_HANDLER_PANEL = "android.app.action.TOGGLE_NOTIFICATION_HANDLER_PANEL";
@@ -4171,7 +4174,6 @@
method @Deprecated public long getInterval();
method @Deprecated public int getNumUpdates();
method @Deprecated @NonNull public String getProvider();
- method public int getQuality();
method @Deprecated public float getSmallestDisplacement();
method @NonNull public android.os.WorkSource getWorkSource();
method public boolean isHiddenFromAppOps();
@@ -4190,11 +4192,11 @@
method @Deprecated @NonNull public android.location.LocationRequest setQuality(int);
method @Deprecated @NonNull public android.location.LocationRequest setSmallestDisplacement(float);
method @Deprecated public void setWorkSource(@Nullable android.os.WorkSource);
- field public static final int ACCURACY_BLOCK = 102; // 0x66
- field public static final int ACCURACY_CITY = 104; // 0x68
- field public static final int ACCURACY_FINE = 100; // 0x64
- field public static final int POWER_HIGH = 203; // 0xcb
- field public static final int POWER_LOW = 201; // 0xc9
+ field @Deprecated public static final int ACCURACY_BLOCK = 102; // 0x66
+ field @Deprecated public static final int ACCURACY_CITY = 104; // 0x68
+ field @Deprecated public static final int ACCURACY_FINE = 100; // 0x64
+ field @Deprecated public static final int POWER_HIGH = 203; // 0xcb
+ field @Deprecated public static final int POWER_LOW = 201; // 0xc9
field @Deprecated public static final int POWER_NONE = 200; // 0xc8
}
@@ -4202,7 +4204,6 @@
method @NonNull @RequiresPermission(android.Manifest.permission.UPDATE_APP_OPS_STATS) public android.location.LocationRequest.Builder setHiddenFromAppOps(boolean);
method @NonNull @RequiresPermission(android.Manifest.permission.WRITE_SECURE_SETTINGS) public android.location.LocationRequest.Builder setLocationSettingsIgnored(boolean);
method @NonNull @RequiresPermission(android.Manifest.permission.LOCATION_HARDWARE) public android.location.LocationRequest.Builder setLowPower(boolean);
- method @NonNull public android.location.LocationRequest.Builder setQuality(int);
method @NonNull @RequiresPermission(android.Manifest.permission.UPDATE_DEVICE_STATS) public android.location.LocationRequest.Builder setWorkSource(@Nullable android.os.WorkSource);
}
@@ -4769,6 +4770,22 @@
field @NonNull public static final android.os.Parcelable.Creator<android.media.tv.DvbDeviceInfo> CREATOR;
}
+ public final class TunedInfo implements android.os.Parcelable {
+ method public int describeContents();
+ method public int getAppTag();
+ method public int getAppType();
+ method @Nullable public android.net.Uri getChannelUri();
+ method @NonNull public String getInputId();
+ method public boolean isForeground();
+ method public boolean isRecordingSession();
+ method public void writeToParcel(@NonNull android.os.Parcel, int);
+ field public static final int APP_TAG_SELF = 0; // 0x0
+ field public static final int APP_TYPE_NON_SYSTEM = 3; // 0x3
+ field public static final int APP_TYPE_SELF = 1; // 0x1
+ field public static final int APP_TYPE_SYSTEM = 2; // 0x2
+ field @NonNull public static final android.os.Parcelable.Creator<android.media.tv.TunedInfo> CREATOR;
+ }
+
public final class TvContentRatingSystemInfo implements android.os.Parcelable {
method public static android.media.tv.TvContentRatingSystemInfo createTvContentRatingSystemInfo(int, android.content.pm.ApplicationInfo);
method public int describeContents();
@@ -4884,6 +4901,7 @@
method @RequiresPermission(android.Manifest.permission.MODIFY_PARENTAL_CONTROLS) public void addBlockedRating(@NonNull android.media.tv.TvContentRating);
method @RequiresPermission(android.Manifest.permission.CAPTURE_TV_INPUT) public boolean captureFrame(String, android.view.Surface, android.media.tv.TvStreamConfig);
method @RequiresPermission(android.Manifest.permission.CAPTURE_TV_INPUT) public java.util.List<android.media.tv.TvStreamConfig> getAvailableTvStreamConfigList(String);
+ method @NonNull @RequiresPermission("com.android.providers.tv.permission.ACCESS_WATCHED_PROGRAMS") public java.util.List<android.media.tv.TunedInfo> getCurrentTunedInfos();
method @NonNull @RequiresPermission("android.permission.DVB_DEVICE") public java.util.List<android.media.tv.DvbDeviceInfo> getDvbDeviceList();
method @RequiresPermission(android.Manifest.permission.TV_INPUT_HARDWARE) public java.util.List<android.media.tv.TvInputHardwareInfo> getHardwareList();
method @RequiresPermission(android.Manifest.permission.READ_CONTENT_RATING_SYSTEMS) public java.util.List<android.media.tv.TvContentRatingSystemInfo> getTvContentRatingSystemList();
@@ -4909,6 +4927,10 @@
method public abstract void onStreamConfigChanged(android.media.tv.TvStreamConfig[]);
}
+ public abstract static class TvInputManager.TvInputCallback {
+ method public void onCurrentTunedInfosUpdated(@NonNull java.util.List<android.media.tv.TunedInfo>);
+ }
+
public abstract class TvInputService extends android.app.Service {
method @Nullable public android.media.tv.TvInputInfo onHardwareAdded(android.media.tv.TvInputHardwareInfo);
method @Nullable public String onHardwareRemoved(android.media.tv.TvInputHardwareInfo);
@@ -5036,6 +5058,7 @@
method @Nullable public android.media.tv.tuner.DemuxCapabilities getDemuxCapabilities();
method @Nullable public android.media.tv.tuner.frontend.FrontendInfo getFrontendInfo();
method @Nullable public android.media.tv.tuner.frontend.FrontendStatus getFrontendStatus(@NonNull int[]);
+ method public int linkFrontendToCiCam(int);
method @Nullable @RequiresPermission(android.Manifest.permission.ACCESS_TV_DESCRAMBLER) public android.media.tv.tuner.Descrambler openDescrambler();
method @Nullable public android.media.tv.tuner.dvr.DvrPlayback openDvrPlayback(long, @NonNull java.util.concurrent.Executor, @NonNull android.media.tv.tuner.dvr.OnPlaybackStatusChangedListener);
method @Nullable public android.media.tv.tuner.dvr.DvrRecorder openDvrRecorder(long, @NonNull java.util.concurrent.Executor, @NonNull android.media.tv.tuner.dvr.OnRecordStatusChangedListener);
@@ -5049,10 +5072,13 @@
method public void setResourceLostListener(@NonNull java.util.concurrent.Executor, @NonNull android.media.tv.tuner.Tuner.OnResourceLostListener);
method public void shareFrontendFromTuner(@NonNull android.media.tv.tuner.Tuner);
method public int tune(@NonNull android.media.tv.tuner.frontend.FrontendSettings);
+ method public int unlinkFrontendToCiCam(int);
method public void updateResourcePriority(int, int);
field public static final int INVALID_AV_SYNC_ID = -1; // 0xffffffff
field public static final int INVALID_FILTER_ID = -1; // 0xffffffff
field public static final long INVALID_FILTER_ID_64BIT = -1L; // 0xffffffffffffffffL
+ field public static final int INVALID_FRONTEND_SETTING_FREQUENCY = -1; // 0xffffffff
+ field public static final int INVALID_LTS_ID = -1; // 0xffffffff
field public static final int INVALID_MMTP_RECORD_EVENT_MPT_SEQUENCE_NUM = -1; // 0xffffffff
field public static final int INVALID_STREAM_ID = 65535; // 0xffff
field public static final long INVALID_TIMESTAMP = -1L; // 0xffffffffffffffffL
@@ -5265,16 +5291,19 @@
method @NonNull public static android.media.tv.tuner.filter.IpFilterConfiguration.Builder builder();
method @NonNull @Size(min=4, max=16) public byte[] getDstIpAddress();
method public int getDstPort();
+ method public int getIpFilterContextId();
method @NonNull @Size(min=4, max=16) public byte[] getSrcIpAddress();
method public int getSrcPort();
method public int getType();
method public boolean isPassthrough();
+ field public static final int INVALID_IP_FILTER_CONTEXT_ID = -1; // 0xffffffff
}
public static final class IpFilterConfiguration.Builder {
method @NonNull public android.media.tv.tuner.filter.IpFilterConfiguration build();
method @NonNull public android.media.tv.tuner.filter.IpFilterConfiguration.Builder setDstIpAddress(@NonNull byte[]);
method @NonNull public android.media.tv.tuner.filter.IpFilterConfiguration.Builder setDstPort(int);
+ method @NonNull public android.media.tv.tuner.filter.IpFilterConfiguration.Builder setIpFilterContextId(int);
method @NonNull public android.media.tv.tuner.filter.IpFilterConfiguration.Builder setPassthrough(boolean);
method @NonNull public android.media.tv.tuner.filter.IpFilterConfiguration.Builder setSettings(@Nullable android.media.tv.tuner.filter.Settings);
method @NonNull public android.media.tv.tuner.filter.IpFilterConfiguration.Builder setSrcIpAddress(@NonNull byte[]);
@@ -5494,9 +5523,13 @@
public class AnalogFrontendSettings extends android.media.tv.tuner.frontend.FrontendSettings {
method @NonNull public static android.media.tv.tuner.frontend.AnalogFrontendSettings.Builder builder();
+ method public int getAftFlag();
method public int getSifStandard();
method public int getSignalType();
method public int getType();
+ field public static final int AFT_FLAG_FALSE = 2; // 0x2
+ field public static final int AFT_FLAG_TRUE = 1; // 0x1
+ field public static final int AFT_FLAG_UNDEFINED = 0; // 0x0
field public static final int SIF_AUTO = 1; // 0x1
field public static final int SIF_BG = 2; // 0x2
field public static final int SIF_BG_A2 = 4; // 0x4
@@ -5529,6 +5562,7 @@
public static class AnalogFrontendSettings.Builder {
method @NonNull public android.media.tv.tuner.frontend.AnalogFrontendSettings build();
+ method @NonNull public android.media.tv.tuner.frontend.AnalogFrontendSettings.Builder setAftFlag(int);
method @IntRange(from=1) @NonNull public android.media.tv.tuner.frontend.AnalogFrontendSettings.Builder setFrequency(int);
method @NonNull public android.media.tv.tuner.frontend.AnalogFrontendSettings.Builder setSifStandard(int);
method @NonNull public android.media.tv.tuner.frontend.AnalogFrontendSettings.Builder setSignalType(int);
@@ -5658,6 +5692,7 @@
method public int getOuterFec();
method public int getSpectralInversion();
method public int getSymbolRate();
+ method public int getTimeInterleaveMode();
method public int getType();
field public static final int ANNEX_A = 1; // 0x1
field public static final int ANNEX_B = 2; // 0x2
@@ -5676,6 +5711,17 @@
field public static final int SPECTRAL_INVERSION_INVERTED = 2; // 0x2
field public static final int SPECTRAL_INVERSION_NORMAL = 1; // 0x1
field public static final int SPECTRAL_INVERSION_UNDEFINED = 0; // 0x0
+ field public static final int TIME_INTERLEAVE_MODE_128_1_0 = 2; // 0x2
+ field public static final int TIME_INTERLEAVE_MODE_128_1_1 = 4; // 0x4
+ field public static final int TIME_INTERLEAVE_MODE_128_2 = 128; // 0x80
+ field public static final int TIME_INTERLEAVE_MODE_128_3 = 256; // 0x100
+ field public static final int TIME_INTERLEAVE_MODE_128_4 = 512; // 0x200
+ field public static final int TIME_INTERLEAVE_MODE_16_8 = 32; // 0x20
+ field public static final int TIME_INTERLEAVE_MODE_32_4 = 16; // 0x10
+ field public static final int TIME_INTERLEAVE_MODE_64_2 = 8; // 0x8
+ field public static final int TIME_INTERLEAVE_MODE_8_16 = 64; // 0x40
+ field public static final int TIME_INTERLEAVE_MODE_AUTO = 1; // 0x1
+ field public static final int TIME_INTERLEAVE_MODE_UNDEFINED = 0; // 0x0
}
public static class DvbcFrontendSettings.Builder {
@@ -5687,6 +5733,7 @@
method @NonNull public android.media.tv.tuner.frontend.DvbcFrontendSettings.Builder setOuterFec(int);
method @NonNull public android.media.tv.tuner.frontend.DvbcFrontendSettings.Builder setSpectralInversion(int);
method @NonNull public android.media.tv.tuner.frontend.DvbcFrontendSettings.Builder setSymbolRate(int);
+ method @NonNull public android.media.tv.tuner.frontend.DvbcFrontendSettings.Builder setTimeInterleaveMode(int);
}
public class DvbsCodeRate {
@@ -5718,6 +5765,7 @@
method public int getModulation();
method public int getPilot();
method public int getRolloff();
+ method public int getScanType();
method public int getStandard();
method public int getSymbolRate();
method public int getType();
@@ -5748,6 +5796,11 @@
field public static final int ROLLOFF_0_35 = 1; // 0x1
field public static final int ROLLOFF_0_5 = 6; // 0x6
field public static final int ROLLOFF_UNDEFINED = 0; // 0x0
+ field public static final int SCAN_TYPE_DIRECT = 1; // 0x1
+ field public static final int SCAN_TYPE_DISEQC = 2; // 0x2
+ field public static final int SCAN_TYPE_JESS = 4; // 0x4
+ field public static final int SCAN_TYPE_UNDEFINED = 0; // 0x0
+ field public static final int SCAN_TYPE_UNICABLE = 3; // 0x3
field public static final int STANDARD_AUTO = 1; // 0x1
field public static final int STANDARD_S = 2; // 0x2
field public static final int STANDARD_S2 = 4; // 0x4
@@ -5765,6 +5818,7 @@
method @NonNull public android.media.tv.tuner.frontend.DvbsFrontendSettings.Builder setModulation(int);
method @NonNull public android.media.tv.tuner.frontend.DvbsFrontendSettings.Builder setPilot(int);
method @NonNull public android.media.tv.tuner.frontend.DvbsFrontendSettings.Builder setRolloff(int);
+ method @NonNull public android.media.tv.tuner.frontend.DvbsFrontendSettings.Builder setScanType(int);
method @NonNull public android.media.tv.tuner.frontend.DvbsFrontendSettings.Builder setStandard(int);
method @NonNull public android.media.tv.tuner.frontend.DvbsFrontendSettings.Builder setSymbolRate(int);
method @NonNull public android.media.tv.tuner.frontend.DvbsFrontendSettings.Builder setVcmMode(int);
@@ -5817,10 +5871,14 @@
field public static final int CODERATE_AUTO = 1; // 0x1
field public static final int CODERATE_UNDEFINED = 0; // 0x0
field public static final int CONSTELLATION_16QAM = 4; // 0x4
+ field public static final int CONSTELLATION_16QAM_R = 64; // 0x40
field public static final int CONSTELLATION_256QAM = 16; // 0x10
+ field public static final int CONSTELLATION_256QAM_R = 256; // 0x100
field public static final int CONSTELLATION_64QAM = 8; // 0x8
+ field public static final int CONSTELLATION_64QAM_R = 128; // 0x80
field public static final int CONSTELLATION_AUTO = 1; // 0x1
field public static final int CONSTELLATION_QPSK = 2; // 0x2
+ field public static final int CONSTELLATION_QPSK_R = 32; // 0x20
field public static final int CONSTELLATION_UNDEFINED = 0; // 0x0
field public static final int GUARD_INTERVAL_19_128 = 64; // 0x40
field public static final int GUARD_INTERVAL_19_256 = 128; // 0x80
@@ -5854,6 +5912,9 @@
field public static final int TRANSMISSION_MODE_4K = 8; // 0x8
field public static final int TRANSMISSION_MODE_8K = 4; // 0x4
field public static final int TRANSMISSION_MODE_AUTO = 1; // 0x1
+ field public static final int TRANSMISSION_MODE_EXTENDED_16K = 256; // 0x100
+ field public static final int TRANSMISSION_MODE_EXTENDED_32K = 512; // 0x200
+ field public static final int TRANSMISSION_MODE_EXTENDED_8K = 128; // 0x80
field public static final int TRANSMISSION_MODE_UNDEFINED = 0; // 0x0
}
@@ -5891,8 +5952,12 @@
}
public abstract class FrontendSettings {
+ method public int getEndFrequency();
method public int getFrequency();
+ method public int getFrontendSpectralInversion();
method public abstract int getType();
+ method @IntRange(from=1) public void setEndFrequency(int);
+ method public void setSpectralInversion(int);
field public static final long FEC_11_15 = 4194304L; // 0x400000L
field public static final long FEC_11_20 = 8388608L; // 0x800000L
field public static final long FEC_11_45 = 16777216L; // 0x1000000L
@@ -5930,6 +5995,9 @@
field public static final long FEC_9_20 = 2097152L; // 0x200000L
field public static final long FEC_AUTO = 1L; // 0x1L
field public static final long FEC_UNDEFINED = 0L; // 0x0L
+ field public static final int FRONTEND_SPECTRAL_INVERSION_INVERTED = 2; // 0x2
+ field public static final int FRONTEND_SPECTRAL_INVERSION_NORMAL = 1; // 0x1
+ field public static final int FRONTEND_SPECTRAL_INVERSION_UNDEFINED = 0; // 0x0
field public static final int TYPE_ANALOG = 1; // 0x1
field public static final int TYPE_ATSC = 2; // 0x2
field public static final int TYPE_ATSC3 = 3; // 0x3
@@ -11040,6 +11108,25 @@
field public static final String MBMS_STREAMING_SERVICE_ACTION = "android.telephony.action.EmbmsStreaming";
}
+ public final class ModemActivityInfo implements android.os.Parcelable {
+ method public int describeContents();
+ method @NonNull public android.telephony.ModemActivityInfo getDelta(@NonNull android.telephony.ModemActivityInfo);
+ method public long getIdleTimeMillis();
+ method public static int getNumTxPowerLevels();
+ method public long getReceiveTimeMillis();
+ method public long getSleepTimeMillis();
+ method public long getTimestampMillis();
+ method public long getTransmitDurationMillisAtPowerLevel(int);
+ method @NonNull public android.util.Range<java.lang.Integer> getTransmitPowerRange(int);
+ method public void writeToParcel(@NonNull android.os.Parcel, int);
+ field @NonNull public static final android.os.Parcelable.Creator<android.telephony.ModemActivityInfo> CREATOR;
+ field public static final int TX_POWER_LEVEL_0 = 0; // 0x0
+ field public static final int TX_POWER_LEVEL_1 = 1; // 0x1
+ field public static final int TX_POWER_LEVEL_2 = 2; // 0x2
+ field public static final int TX_POWER_LEVEL_3 = 3; // 0x3
+ field public static final int TX_POWER_LEVEL_4 = 4; // 0x4
+ }
+
public final class NetworkRegistrationInfo implements android.os.Parcelable {
method @Nullable public android.telephony.DataSpecificRegistrationInfo getDataSpecificInfo();
method public int getRegistrationState();
diff --git a/api/system-lint-baseline.txt b/api/system-lint-baseline.txt
index 7195144..773ecd03 100644
--- a/api/system-lint-baseline.txt
+++ b/api/system-lint-baseline.txt
@@ -159,8 +159,6 @@
MissingNullability: android.telephony.ModemActivityInfo#writeToParcel(android.os.Parcel, int) parameter #0:
-MissingNullability: android.telephony.ModemActivityInfo.TransmitPower#toString():
-
MissingNullability: android.telephony.NetworkService#onUnbind(android.content.Intent) parameter #0:
MissingNullability: android.telephony.SmsCbCmasInfo#toString():
diff --git a/api/test-current.txt b/api/test-current.txt
index e7c6445..b34c948 100644
--- a/api/test-current.txt
+++ b/api/test-current.txt
@@ -14,6 +14,7 @@
field public static final String FORCE_STOP_PACKAGES = "android.permission.FORCE_STOP_PACKAGES";
field public static final String MANAGE_ACTIVITY_STACKS = "android.permission.MANAGE_ACTIVITY_STACKS";
field public static final String MANAGE_CRATES = "android.permission.MANAGE_CRATES";
+ field public static final String MANAGE_NOTIFICATION_LISTENERS = "android.permission.MANAGE_NOTIFICATION_LISTENERS";
field public static final String MANAGE_ROLLBACKS = "android.permission.MANAGE_ROLLBACKS";
field public static final String NETWORK_SETTINGS = "android.permission.NETWORK_SETTINGS";
field public static final String NETWORK_STACK = "android.permission.NETWORK_STACK";
@@ -79,6 +80,7 @@
}
public class ActivityManager {
+ method @RequiresPermission(android.Manifest.permission.SET_ACTIVITY_WATCHER) public void addHomeVisibilityListener(@NonNull java.util.concurrent.Executor, @NonNull android.app.HomeVisibilityListener);
method @RequiresPermission(android.Manifest.permission.PACKAGE_USAGE_STATS) public void addOnUidImportanceListener(android.app.ActivityManager.OnUidImportanceListener, int);
method public void alwaysShowUnsupportedCompileSdkWarning(android.content.ComponentName);
method @RequiresPermission(android.Manifest.permission.FORCE_STOP_PACKAGES) public void forceStopPackage(String);
@@ -88,6 +90,7 @@
method @RequiresPermission(android.Manifest.permission.INJECT_EVENTS) public void holdLock(int);
method public static boolean isHighEndGfx();
method @RequiresPermission(android.Manifest.permission.FORCE_STOP_PACKAGES) public void killProcessesWhenImperceptible(@NonNull int[], @NonNull String);
+ method @RequiresPermission(android.Manifest.permission.SET_ACTIVITY_WATCHER) public void removeHomeVisibilityListener(@NonNull android.app.HomeVisibilityListener);
method @RequiresPermission(android.Manifest.permission.PACKAGE_USAGE_STATS) public void removeOnUidImportanceListener(android.app.ActivityManager.OnUidImportanceListener);
method @RequiresPermission(android.Manifest.permission.RESET_APP_ERRORS) public void resetAppErrors();
method public static void resumeAppSwitches() throws android.os.RemoteException;
@@ -458,6 +461,11 @@
method @RequiresPermission(android.Manifest.permission.WRITE_DREAM_STATE) public void stopDream();
}
+ public abstract class HomeVisibilityListener {
+ ctor public HomeVisibilityListener();
+ method public abstract void onHomeVisibilityChanged(boolean);
+ }
+
public final class NotificationChannel implements android.os.Parcelable {
method public int getOriginalImportance();
method public boolean isBlockable();
@@ -487,9 +495,11 @@
method @NonNull public java.util.List<java.lang.String> getAllowedAssistantAdjustments();
method @Nullable public android.content.ComponentName getAllowedNotificationAssistant();
method public android.content.ComponentName getEffectsSuppressor();
+ method @NonNull @RequiresPermission(android.Manifest.permission.MANAGE_NOTIFICATION_LISTENERS) public java.util.List<android.content.ComponentName> getEnabledNotificationListeners();
method public boolean isNotificationAssistantAccessGranted(@NonNull android.content.ComponentName);
method public boolean matchesCallFilter(android.os.Bundle);
method public void setNotificationAssistantAccessGranted(@Nullable android.content.ComponentName, boolean);
+ method @RequiresPermission(android.Manifest.permission.MANAGE_NOTIFICATION_LISTENERS) public void setNotificationListenerAccessGranted(@NonNull android.content.ComponentName, boolean);
method public void updateNotificationChannel(@NonNull String, int, @NonNull android.app.NotificationChannel);
}
@@ -1227,20 +1237,19 @@
package android.hardware.biometrics {
public class BiometricManager {
- method @NonNull @RequiresPermission(android.Manifest.permission.TEST_BIOMETRIC) public android.hardware.biometrics.BiometricTestSession getTestSession();
+ method @NonNull @RequiresPermission(android.Manifest.permission.TEST_BIOMETRIC) public android.hardware.biometrics.BiometricTestSession createTestSession(int);
+ method @NonNull @RequiresPermission(android.Manifest.permission.TEST_BIOMETRIC) public java.util.List<android.hardware.biometrics.SensorProperties> getSensorProperties();
}
public class BiometricTestSession implements java.lang.AutoCloseable {
- method @RequiresPermission(android.Manifest.permission.TEST_BIOMETRIC) public void authenticateReject(int, int);
- method @RequiresPermission(android.Manifest.permission.TEST_BIOMETRIC) public void authenticateSuccess(int, int);
+ method @RequiresPermission(android.Manifest.permission.TEST_BIOMETRIC) public void acceptAuthentication(int);
+ method @RequiresPermission(android.Manifest.permission.TEST_BIOMETRIC) public void cleanupInternalState(int);
method @RequiresPermission(android.Manifest.permission.TEST_BIOMETRIC) public void close();
- method @RequiresPermission(android.Manifest.permission.TEST_BIOMETRIC) public void enableTestHal(int, boolean);
- method @RequiresPermission(android.Manifest.permission.TEST_BIOMETRIC) public void enrollFinish(int, int);
- method @RequiresPermission(android.Manifest.permission.TEST_BIOMETRIC) public void enrollStart(int, int);
- method @NonNull @RequiresPermission(android.Manifest.permission.TEST_BIOMETRIC) public java.util.List<android.hardware.biometrics.SensorProperties> getSensorProperties();
- method @RequiresPermission(android.Manifest.permission.TEST_BIOMETRIC) public void internalCleanup(int, int);
- method @RequiresPermission(android.Manifest.permission.TEST_BIOMETRIC) public void notifyAcquired(int, int);
- method @RequiresPermission(android.Manifest.permission.TEST_BIOMETRIC) public void notifyError(int, int);
+ method @RequiresPermission(android.Manifest.permission.TEST_BIOMETRIC) public void finishEnroll(int);
+ method @RequiresPermission(android.Manifest.permission.TEST_BIOMETRIC) public void notifyAcquired(int);
+ method @RequiresPermission(android.Manifest.permission.TEST_BIOMETRIC) public void notifyError(int);
+ method @RequiresPermission(android.Manifest.permission.TEST_BIOMETRIC) public void rejectAuthentication(int);
+ method @RequiresPermission(android.Manifest.permission.TEST_BIOMETRIC) public void startEnroll(int);
}
public class SensorProperties {
@@ -1361,7 +1370,8 @@
package android.hardware.fingerprint {
@Deprecated public class FingerprintManager {
- method @Deprecated @NonNull @RequiresPermission(android.Manifest.permission.TEST_BIOMETRIC) public android.hardware.biometrics.BiometricTestSession getTestSession();
+ method @Deprecated @NonNull @RequiresPermission(android.Manifest.permission.TEST_BIOMETRIC) public android.hardware.biometrics.BiometricTestSession createTestSession(int);
+ method @Deprecated @NonNull @RequiresPermission(android.Manifest.permission.TEST_BIOMETRIC) public java.util.List<android.hardware.biometrics.SensorProperties> getSensorProperties();
}
}
@@ -1767,11 +1777,11 @@
method public boolean isHiddenFromAppOps();
method public boolean isLocationSettingsIgnored();
method public boolean isLowPower();
- field public static final int ACCURACY_BLOCK = 102; // 0x66
- field public static final int ACCURACY_CITY = 104; // 0x68
- field public static final int ACCURACY_FINE = 100; // 0x64
- field public static final int POWER_HIGH = 203; // 0xcb
- field public static final int POWER_LOW = 201; // 0xc9
+ field @Deprecated public static final int ACCURACY_BLOCK = 102; // 0x66
+ field @Deprecated public static final int ACCURACY_CITY = 104; // 0x68
+ field @Deprecated public static final int ACCURACY_FINE = 100; // 0x64
+ field @Deprecated public static final int POWER_HIGH = 203; // 0xcb
+ field @Deprecated public static final int POWER_LOW = 201; // 0xc9
}
public static final class LocationRequest.Builder {
@@ -4233,6 +4243,27 @@
field public static final String MBMS_STREAMING_SERVICE_OVERRIDE_METADATA = "mbms-streaming-service-override";
}
+ public final class ModemActivityInfo implements android.os.Parcelable {
+ ctor public ModemActivityInfo(long, int, int, @NonNull int[], int);
+ method public int describeContents();
+ method @NonNull public android.telephony.ModemActivityInfo getDelta(@NonNull android.telephony.ModemActivityInfo);
+ method public long getIdleTimeMillis();
+ method public static int getNumTxPowerLevels();
+ method public long getReceiveTimeMillis();
+ method public long getSleepTimeMillis();
+ method public long getTimestampMillis();
+ method public long getTransmitDurationMillisAtPowerLevel(int);
+ method @NonNull public android.util.Range<java.lang.Integer> getTransmitPowerRange(int);
+ method public boolean isValid();
+ method public void writeToParcel(@NonNull android.os.Parcel, int);
+ field @NonNull public static final android.os.Parcelable.Creator<android.telephony.ModemActivityInfo> CREATOR;
+ field public static final int TX_POWER_LEVEL_0 = 0; // 0x0
+ field public static final int TX_POWER_LEVEL_1 = 1; // 0x1
+ field public static final int TX_POWER_LEVEL_2 = 2; // 0x2
+ field public static final int TX_POWER_LEVEL_3 = 3; // 0x3
+ field public static final int TX_POWER_LEVEL_4 = 4; // 0x4
+ }
+
public final class NetworkRegistrationInfo implements android.os.Parcelable {
method @Nullable public android.telephony.DataSpecificRegistrationInfo getDataSpecificInfo();
method public int getRegistrationState();
@@ -5785,6 +5816,15 @@
field public static final int FEATURE_WINDOW_TOKENS = 2; // 0x2
}
+ public final class TaskAppearedInfo implements android.os.Parcelable {
+ ctor public TaskAppearedInfo(@NonNull android.app.ActivityManager.RunningTaskInfo, @NonNull android.view.SurfaceControl);
+ method public int describeContents();
+ method @NonNull public android.view.SurfaceControl getLeash();
+ method @NonNull public android.app.ActivityManager.RunningTaskInfo getTaskInfo();
+ method public void writeToParcel(@NonNull android.os.Parcel, int);
+ field @NonNull public static final android.os.Parcelable.Creator<android.window.TaskAppearedInfo> CREATOR;
+ }
+
public class TaskOrganizer extends android.window.WindowOrganizer {
ctor public TaskOrganizer();
method @Nullable @RequiresPermission(android.Manifest.permission.MANAGE_ACTIVITY_STACKS) public android.app.ActivityManager.RunningTaskInfo createRootTask(int, int);
@@ -5796,10 +5836,10 @@
method @BinderThread public void onTaskAppeared(@NonNull android.app.ActivityManager.RunningTaskInfo, @NonNull android.view.SurfaceControl);
method @BinderThread public void onTaskInfoChanged(@NonNull android.app.ActivityManager.RunningTaskInfo);
method @BinderThread public void onTaskVanished(@NonNull android.app.ActivityManager.RunningTaskInfo);
- method @RequiresPermission(android.Manifest.permission.MANAGE_ACTIVITY_STACKS) public final void registerOrganizer();
+ method @CallSuper @NonNull @RequiresPermission(android.Manifest.permission.MANAGE_ACTIVITY_STACKS) public java.util.List<android.window.TaskAppearedInfo> registerOrganizer();
method @RequiresPermission(android.Manifest.permission.MANAGE_ACTIVITY_STACKS) public void setInterceptBackPressedOnTaskRoot(@NonNull android.window.WindowContainerToken, boolean);
method @RequiresPermission(android.Manifest.permission.MANAGE_ACTIVITY_STACKS) public void setLaunchRoot(int, @NonNull android.window.WindowContainerToken);
- method @RequiresPermission(android.Manifest.permission.MANAGE_ACTIVITY_STACKS) public final void unregisterOrganizer();
+ method @CallSuper @RequiresPermission(android.Manifest.permission.MANAGE_ACTIVITY_STACKS) public void unregisterOrganizer();
}
public final class WindowContainerToken implements android.os.Parcelable {
diff --git a/core/java/android/accessibilityservice/AccessibilityGestureEvent.java b/core/java/android/accessibilityservice/AccessibilityGestureEvent.java
index 25729ab..e3139eb 100644
--- a/core/java/android/accessibilityservice/AccessibilityGestureEvent.java
+++ b/core/java/android/accessibilityservice/AccessibilityGestureEvent.java
@@ -20,6 +20,7 @@
import static android.accessibilityservice.AccessibilityService.GESTURE_2_FINGER_DOUBLE_TAP;
import static android.accessibilityservice.AccessibilityService.GESTURE_2_FINGER_DOUBLE_TAP_AND_HOLD;
import static android.accessibilityservice.AccessibilityService.GESTURE_2_FINGER_SINGLE_TAP;
+import static android.accessibilityservice.AccessibilityService.GESTURE_2_FINGER_SINGLE_TAP_AND_HOLD;
import static android.accessibilityservice.AccessibilityService.GESTURE_2_FINGER_SWIPE_DOWN;
import static android.accessibilityservice.AccessibilityService.GESTURE_2_FINGER_SWIPE_LEFT;
import static android.accessibilityservice.AccessibilityService.GESTURE_2_FINGER_SWIPE_RIGHT;
@@ -28,11 +29,13 @@
import static android.accessibilityservice.AccessibilityService.GESTURE_3_FINGER_DOUBLE_TAP;
import static android.accessibilityservice.AccessibilityService.GESTURE_3_FINGER_DOUBLE_TAP_AND_HOLD;
import static android.accessibilityservice.AccessibilityService.GESTURE_3_FINGER_SINGLE_TAP;
+import static android.accessibilityservice.AccessibilityService.GESTURE_3_FINGER_SINGLE_TAP_AND_HOLD;
import static android.accessibilityservice.AccessibilityService.GESTURE_3_FINGER_SWIPE_DOWN;
import static android.accessibilityservice.AccessibilityService.GESTURE_3_FINGER_SWIPE_LEFT;
import static android.accessibilityservice.AccessibilityService.GESTURE_3_FINGER_SWIPE_RIGHT;
import static android.accessibilityservice.AccessibilityService.GESTURE_3_FINGER_SWIPE_UP;
import static android.accessibilityservice.AccessibilityService.GESTURE_3_FINGER_TRIPLE_TAP;
+import static android.accessibilityservice.AccessibilityService.GESTURE_3_FINGER_TRIPLE_TAP_AND_HOLD;
import static android.accessibilityservice.AccessibilityService.GESTURE_4_FINGER_DOUBLE_TAP;
import static android.accessibilityservice.AccessibilityService.GESTURE_4_FINGER_DOUBLE_TAP_AND_HOLD;
import static android.accessibilityservice.AccessibilityService.GESTURE_4_FINGER_SINGLE_TAP;
@@ -85,13 +88,16 @@
/** @hide */
@IntDef(prefix = { "GESTURE_" }, value = {
GESTURE_2_FINGER_SINGLE_TAP,
+ GESTURE_2_FINGER_SINGLE_TAP_AND_HOLD,
GESTURE_2_FINGER_DOUBLE_TAP,
GESTURE_2_FINGER_DOUBLE_TAP_AND_HOLD,
GESTURE_2_FINGER_TRIPLE_TAP,
GESTURE_3_FINGER_SINGLE_TAP,
+ GESTURE_3_FINGER_SINGLE_TAP_AND_HOLD,
GESTURE_3_FINGER_DOUBLE_TAP,
GESTURE_3_FINGER_DOUBLE_TAP_AND_HOLD,
GESTURE_3_FINGER_TRIPLE_TAP,
+ GESTURE_3_FINGER_TRIPLE_TAP_AND_HOLD,
GESTURE_DOUBLE_TAP,
GESTURE_DOUBLE_TAP_AND_HOLD,
GESTURE_SWIPE_UP,
@@ -180,15 +186,21 @@
private static String eventTypeToString(int eventType) {
switch (eventType) {
case GESTURE_2_FINGER_SINGLE_TAP: return "GESTURE_2_FINGER_SINGLE_TAP";
+ case GESTURE_2_FINGER_SINGLE_TAP_AND_HOLD:
+ return "GESTURE_2_FINGER_SINGLE_TAP_AND_HOLD";
case GESTURE_2_FINGER_DOUBLE_TAP: return "GESTURE_2_FINGER_DOUBLE_TAP";
case GESTURE_2_FINGER_DOUBLE_TAP_AND_HOLD:
return "GESTURE_2_FINGER_DOUBLE_TAP_AND_HOLD";
case GESTURE_2_FINGER_TRIPLE_TAP: return "GESTURE_2_FINGER_TRIPLE_TAP";
case GESTURE_3_FINGER_SINGLE_TAP: return "GESTURE_3_FINGER_SINGLE_TAP";
+ case GESTURE_3_FINGER_SINGLE_TAP_AND_HOLD:
+ return "GESTURE_3_FINGER_SINGLE_TAP_AND_HOLD";
case GESTURE_3_FINGER_DOUBLE_TAP: return "GESTURE_3_FINGER_DOUBLE_TAP";
case GESTURE_3_FINGER_DOUBLE_TAP_AND_HOLD:
return "GESTURE_3_FINGER_DOUBLE_TAP_AND_HOLD";
case GESTURE_3_FINGER_TRIPLE_TAP: return "GESTURE_3_FINGER_TRIPLE_TAP";
+ case GESTURE_3_FINGER_TRIPLE_TAP_AND_HOLD:
+ return "GESTURE_3_FINGER_TRIPLE_TAP_AND_HOLD";
case GESTURE_4_FINGER_SINGLE_TAP: return "GESTURE_4_FINGER_SINGLE_TAP";
case GESTURE_4_FINGER_DOUBLE_TAP: return "GESTURE_4_FINGER_DOUBLE_TAP";
case GESTURE_4_FINGER_DOUBLE_TAP_AND_HOLD:
diff --git a/core/java/android/accessibilityservice/AccessibilityService.java b/core/java/android/accessibilityservice/AccessibilityService.java
index b5b0ce3..7c6d448 100644
--- a/core/java/android/accessibilityservice/AccessibilityService.java
+++ b/core/java/android/accessibilityservice/AccessibilityService.java
@@ -421,6 +421,15 @@
/** The user has performed a three-finger double tap and hold gesture on the touch screen. */
public static final int GESTURE_3_FINGER_DOUBLE_TAP_AND_HOLD = 41;
+ /** The user has performed a two-finger single-tap and hold gesture on the touch screen. */
+ public static final int GESTURE_2_FINGER_SINGLE_TAP_AND_HOLD = 43;
+
+ /** The user has performed a three-finger single-tap and hold gesture on the touch screen. */
+ public static final int GESTURE_3_FINGER_SINGLE_TAP_AND_HOLD = 44;
+
+ /** The user has performed a three-finger triple-tap and hold gesture on the touch screen. */
+ public static final int GESTURE_3_FINGER_TRIPLE_TAP_AND_HOLD = 45;
+
/** The user has performed a two-finger double tap and hold gesture on the touch screen. */
public static final int GESTURE_4_FINGER_DOUBLE_TAP_AND_HOLD = 42;
diff --git a/core/java/android/app/ActivityManager.java b/core/java/android/app/ActivityManager.java
index e75d2f6..30efb48 100644
--- a/core/java/android/app/ActivityManager.java
+++ b/core/java/android/app/ActivityManager.java
@@ -100,6 +100,7 @@
import java.util.Collections;
import java.util.List;
import java.util.Locale;
+import java.util.concurrent.Executor;
/**
* <p>
@@ -4752,31 +4753,43 @@
}
/**
- * Register with {@link HomeVisibilityObserver} with ActivityManager.
- * TODO: b/144351078 expose as SystemApi
+ * Register to be notified when the visibility of the home screen changes.
+ *
+ * @param executor The executor on which the listener should be called.
+ * @param listener The listener that is called when home visibility changes.
* @hide
*/
- public void registerHomeVisibilityObserver(@NonNull HomeVisibilityObserver observer) {
- Preconditions.checkNotNull(observer);
+ @SystemApi(client = SystemApi.Client.MODULE_LIBRARIES)
+ @TestApi
+ @RequiresPermission(android.Manifest.permission.SET_ACTIVITY_WATCHER)
+ public void addHomeVisibilityListener(@NonNull Executor executor,
+ @NonNull HomeVisibilityListener listener) {
+ Preconditions.checkNotNull(listener);
+ Preconditions.checkNotNull(executor);
try {
- observer.init(mContext, this);
- getService().registerProcessObserver(observer.mObserver);
+ listener.init(mContext, executor, this);
+ getService().registerProcessObserver(listener.mObserver);
// Notify upon first registration.
- observer.onHomeVisibilityChanged(observer.mIsHomeActivityVisible);
+ executor.execute(() ->
+ listener.onHomeVisibilityChanged(listener.mIsHomeActivityVisible));
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
}
/**
- * Unregister with {@link HomeVisibilityObserver} with ActivityManager.
- * TODO: b/144351078 expose as SystemApi
+ * Removes a listener that was previously added with {@link #addHomeVisibilityListener}.
+ *
+ * @param listener The listener that was previously added.
* @hide
*/
- public void unregisterHomeVisibilityObserver(@NonNull HomeVisibilityObserver observer) {
- Preconditions.checkNotNull(observer);
+ @SystemApi(client = SystemApi.Client.MODULE_LIBRARIES)
+ @TestApi
+ @RequiresPermission(android.Manifest.permission.SET_ACTIVITY_WATCHER)
+ public void removeHomeVisibilityListener(@NonNull HomeVisibilityListener listener) {
+ Preconditions.checkNotNull(listener);
try {
- getService().unregisterProcessObserver(observer.mObserver);
+ getService().unregisterProcessObserver(listener.mObserver);
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
diff --git a/core/java/android/app/HomeVisibilityListener.java b/core/java/android/app/HomeVisibilityListener.java
new file mode 100644
index 0000000..c6e5699
--- /dev/null
+++ b/core/java/android/app/HomeVisibilityListener.java
@@ -0,0 +1,112 @@
+/*
+ * 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.
+ */
+
+package android.app;
+
+import android.annotation.SuppressLint;
+import android.annotation.SystemApi;
+import android.annotation.TestApi;
+import android.content.Context;
+import android.os.Binder;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Objects;
+import java.util.concurrent.Executor;
+
+/**
+ * A listener that will be invoked when the visibility of the home screen changes.
+ * Register this callback via {@link ActivityManager#addHomeVisibilityListener}
+ * @hide
+ */
+// This is a single-method listener that needs a bunch of supporting code, so it can't be an
+// interface
+@SuppressLint("ListenerInterface")
+@SystemApi(client = SystemApi.Client.MODULE_LIBRARIES)
+@TestApi
+public abstract class HomeVisibilityListener {
+ private Context mContext;
+ private ActivityManager mActivityManager;
+ private Executor mExecutor;
+ /** @hide */
+ android.app.IProcessObserver.Stub mObserver;
+ /** @hide */
+ boolean mIsHomeActivityVisible;
+
+ /** @hide */
+ void init(Context context, Executor executor, ActivityManager activityManager) {
+ mContext = context;
+ mActivityManager = activityManager;
+ mIsHomeActivityVisible = isHomeActivityVisible();
+ mExecutor = executor;
+ }
+
+ /**
+ * Called when the visibility of the home screen changes.
+ *
+ * @param isHomeActivityVisible Whether the home screen activity is now visible.
+ */
+ public abstract void onHomeVisibilityChanged(boolean isHomeActivityVisible);
+
+ public HomeVisibilityListener() {
+ mObserver = new android.app.IProcessObserver.Stub() {
+ @Override
+ public void onForegroundActivitiesChanged(int pid, int uid, boolean fg) {
+ refreshHomeVisibility();
+ }
+
+ @Override
+ public void onForegroundServicesChanged(int pid, int uid, int fgServiceTypes) {
+ }
+
+ @Override
+ public void onProcessDied(int pid, int uid) {
+ refreshHomeVisibility();
+ }
+
+ private void refreshHomeVisibility() {
+ boolean isHomeActivityVisible = isHomeActivityVisible();
+ if (mIsHomeActivityVisible != isHomeActivityVisible) {
+ mIsHomeActivityVisible = isHomeActivityVisible;
+ Binder.withCleanCallingIdentity(() ->
+ mExecutor.execute(() ->
+ onHomeVisibilityChanged(mIsHomeActivityVisible)));
+ }
+ }
+ };
+ }
+
+ private boolean isHomeActivityVisible() {
+ List<ActivityManager.RunningTaskInfo> tasks = mActivityManager.getRunningTasks(1);
+ if (tasks == null || tasks.isEmpty()) {
+ return false;
+ }
+
+ String top = tasks.get(0).topActivity.getPackageName();
+ if (top == null) {
+ return false;
+ }
+
+ // We can assume that the screen is idle if the home application is in the foreground.
+ String defaultHomePackage = mContext.getPackageManager()
+ .getHomeActivities(new ArrayList<>()).getPackageName();
+ if (Objects.equals(top, defaultHomePackage)) {
+ return true;
+ }
+
+ return false;
+ }
+}
diff --git a/core/java/android/app/HomeVisibilityObserver.java b/core/java/android/app/HomeVisibilityObserver.java
deleted file mode 100644
index 8422c6f..0000000
--- a/core/java/android/app/HomeVisibilityObserver.java
+++ /dev/null
@@ -1,97 +0,0 @@
-/*
- * 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.
- */
-
-package android.app;
-
-import android.content.Context;
-import android.content.Intent;
-import android.content.pm.PackageManager;
-import android.content.pm.ResolveInfo;
-
-import java.util.List;
-
-/**
- * An observer / callback to create and register by
- * {@link ActivityManager#registerHomeVisibilityObserver} so that it's triggered when
- * visibility of home page changes.
- * TODO: b/144351078 expose as SystemApi
- * @hide
- */
-public abstract class HomeVisibilityObserver {
- private Context mContext;
- private ActivityManager mActivityManager;
- /** @hide */
- IProcessObserver.Stub mObserver;
- /** @hide */
- boolean mIsHomeActivityVisible;
-
- /** @hide */
- void init(Context context, ActivityManager activityManager) {
- mContext = context;
- mActivityManager = activityManager;
- mIsHomeActivityVisible = isHomeActivityVisible();
- }
-
- /**
- * The API that needs implemented and will be triggered when activity on home page changes.
- */
- public abstract void onHomeVisibilityChanged(boolean isHomeActivityVisible);
-
- public HomeVisibilityObserver() {
- mObserver = new IProcessObserver.Stub() {
- @Override
- public void onForegroundActivitiesChanged(int pid, int uid, boolean fg) {
- boolean isHomeActivityVisible = isHomeActivityVisible();
- if (mIsHomeActivityVisible != isHomeActivityVisible) {
- mIsHomeActivityVisible = isHomeActivityVisible;
- onHomeVisibilityChanged(mIsHomeActivityVisible);
- }
- }
-
- @Override
- public void onForegroundServicesChanged(int pid, int uid, int fgServiceTypes) {
- }
-
- @Override
- public void onProcessDied(int pid, int uid) {
- }
- };
- }
-
- private boolean isHomeActivityVisible() {
- List<ActivityManager.RunningTaskInfo> tasks = mActivityManager.getRunningTasks(1);
- if (tasks == null || tasks.isEmpty()) {
- return false;
- }
-
- String top = tasks.get(0).topActivity.getPackageName();
- if (top == null) {
- return false;
- }
-
- // We can assume that the screen is idle if the home application is in the foreground.
- final Intent intent = new Intent(Intent.ACTION_MAIN, null);
- intent.addCategory(Intent.CATEGORY_HOME);
-
- ResolveInfo info = mContext.getPackageManager().resolveActivity(intent,
- PackageManager.MATCH_DEFAULT_ONLY);
- if (info != null && top.equals(info.activityInfo.packageName)) {
- return true;
- }
-
- return false;
- }
-}
diff --git a/core/java/android/app/IActivityTaskManager.aidl b/core/java/android/app/IActivityTaskManager.aidl
index 66007e5..7530229 100644
--- a/core/java/android/app/IActivityTaskManager.aidl
+++ b/core/java/android/app/IActivityTaskManager.aidl
@@ -165,7 +165,8 @@
int getTaskForActivity(in IBinder token, in boolean onlyRoot);
/** Finish all activities that were started for result from the specified activity. */
void finishSubActivity(in IBinder token, in String resultWho, int requestCode);
- ParceledListSlice getRecentTasks(int maxNum, int flags, int userId);
+ ParceledListSlice<ActivityManager.RecentTaskInfo> getRecentTasks(int maxNum, int flags,
+ int userId);
boolean willActivityBeVisible(in IBinder token);
void setRequestedOrientation(in IBinder token, int requestedOrientation);
int getRequestedOrientation(in IBinder token);
diff --git a/core/java/android/app/NotificationManager.java b/core/java/android/app/NotificationManager.java
index fe89366..d442f5f 100644
--- a/core/java/android/app/NotificationManager.java
+++ b/core/java/android/app/NotificationManager.java
@@ -1567,8 +1567,20 @@
}
}
- /** @hide */
- public void setNotificationListenerAccessGranted(ComponentName listener, boolean granted) {
+ /**
+ * Grants/revokes Notification Listener access to the given component for current user.
+ * To grant access for a particular user, obtain this service by using the {@link Context}
+ * provided by {@link Context#createPackageContextAsUser}
+ *
+ * @param listener Name of component to grant/revoke access
+ * @param granted Grant/revoke access
+ * @hide
+ */
+ @SystemApi
+ @TestApi
+ @RequiresPermission(android.Manifest.permission.MANAGE_NOTIFICATION_LISTENERS)
+ public void setNotificationListenerAccessGranted(
+ @NonNull ComponentName listener, boolean granted) {
INotificationManager service = getService();
try {
service.setNotificationListenerAccessGranted(listener, granted);
@@ -1610,6 +1622,21 @@
}
}
+ /**
+ * Gets the list of enabled notification listener components for current user.
+ * To query for a particular user, obtain this service by using the {@link Context}
+ * provided by {@link Context#createPackageContextAsUser}
+ *
+ * @return the list of {@link ComponentName}s of the notification listeners
+ * @hide
+ */
+ @SystemApi
+ @TestApi
+ @RequiresPermission(android.Manifest.permission.MANAGE_NOTIFICATION_LISTENERS)
+ public @NonNull List<ComponentName> getEnabledNotificationListeners() {
+ return getEnabledNotificationListeners(mContext.getUserId());
+ }
+
/** @hide */
public List<ComponentName> getEnabledNotificationListeners(int userId) {
INotificationManager service = getService();
diff --git a/core/java/android/app/PendingIntent.java b/core/java/android/app/PendingIntent.java
index e8937a8..8054cdb 100644
--- a/core/java/android/app/PendingIntent.java
+++ b/core/java/android/app/PendingIntent.java
@@ -363,6 +363,7 @@
* parameters. May return null only if {@link #FLAG_NO_CREATE} has been
* supplied.
*/
+ @SuppressWarnings("AndroidFrameworkPendingIntentMutability")
public static PendingIntent getActivity(Context context, int requestCode,
Intent intent, @Flags int flags) {
return getActivity(context, requestCode, intent, flags, null);
@@ -489,6 +490,7 @@
* parameters. May return null only if {@link #FLAG_NO_CREATE} has been
* supplied.
*/
+ @SuppressWarnings("AndroidFrameworkPendingIntentMutability")
public static PendingIntent getActivities(Context context, int requestCode,
@NonNull Intent[] intents, @Flags int flags) {
return getActivities(context, requestCode, intents, flags, null);
@@ -611,6 +613,7 @@
* parameters. May return null only if {@link #FLAG_NO_CREATE} has been
* supplied.
*/
+ @SuppressWarnings("AndroidFrameworkPendingIntentMutability")
public static PendingIntent getBroadcast(Context context, int requestCode,
Intent intent, @Flags int flags) {
return getBroadcastAsUser(context, requestCode, intent, flags, context.getUser());
diff --git a/core/java/android/app/TaskStackBuilder.java b/core/java/android/app/TaskStackBuilder.java
index b99b327..e238046 100644
--- a/core/java/android/app/TaskStackBuilder.java
+++ b/core/java/android/app/TaskStackBuilder.java
@@ -264,6 +264,7 @@
*
* @return The obtained PendingIntent
*/
+ @SuppressWarnings("AndroidFrameworkPendingIntentMutability")
public PendingIntent getPendingIntent(int requestCode, @PendingIntent.Flags int flags,
Bundle options) {
if (mIntents.isEmpty()) {
@@ -278,6 +279,7 @@
/**
* @hide
*/
+ @SuppressWarnings("AndroidFrameworkPendingIntentMutability")
public PendingIntent getPendingIntent(int requestCode, int flags, Bundle options,
UserHandle user) {
if (mIntents.isEmpty()) {
diff --git a/core/java/android/content/Intent.java b/core/java/android/content/Intent.java
index 2f1254f..a14e21b 100644
--- a/core/java/android/content/Intent.java
+++ b/core/java/android/content/Intent.java
@@ -2744,7 +2744,6 @@
* </ul>
*
* <p class="note">This is a protected intent that can only be sent by the system.
- * @hide
*/
@SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
public static final String ACTION_PACKAGE_STARTABLE = "android.intent.action.PACKAGE_STARTABLE";
@@ -2755,13 +2754,13 @@
* <ul>
* <li> {@link #EXTRA_UID} containing the integer uid assigned to the package. </li>
* <li> {@link #EXTRA_PACKAGE_NAME} containing the package name. </li>
- * <li> {@link #EXTRA_REASON} containing the integer indicating the reason for the state change,
+ * <li> {@link #EXTRA_UNSTARTABLE_REASON} containing the integer indicating the reason for
+ * the state change,
* @see PackageManager.UnstartableReason
* </li>
* </ul>
*
* <p class="note">This is a protected intent that can only be sent by the system.
- * @hide
*/
@SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
public static final String ACTION_PACKAGE_UNSTARTABLE =
@@ -2776,7 +2775,6 @@
* </ul>
*
* <p class="note">This is a protected intent that can only be sent by the system.
- * @hide
*/
@SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
public static final String ACTION_PACKAGE_FULLY_LOADED =
@@ -6015,6 +6013,13 @@
*/
public static final String EXTRA_LOCUS_ID = "android.intent.extra.LOCUS_ID";
+ /**
+ * Intent extra: the reason that the package associated with this intent has become unstartable.
+ *
+ * <p>Type: String
+ */
+ public static final String EXTRA_UNSTARTABLE_REASON = "android.intent.extra.UNSTARTABLE_REASON";
+
// ---------------------------------------------------------------------
// ---------------------------------------------------------------------
// Intent flags (see mFlags variable).
diff --git a/core/java/android/content/pm/PackageManager.java b/core/java/android/content/pm/PackageManager.java
index 1a992f5..32ae105 100644
--- a/core/java/android/content/pm/PackageManager.java
+++ b/core/java/android/content/pm/PackageManager.java
@@ -3790,8 +3790,8 @@
* @hide
*/
@IntDef({UNSTARTABLE_REASON_UNKNOWN,
- UNSTARTABLE_REASON_DATALOADER_TRANSPORT,
- UNSTARTABLE_REASON_DATALOADER_STORAGE
+ UNSTARTABLE_REASON_CONNECTION_ERROR,
+ UNSTARTABLE_REASON_INSUFFICIENT_STORAGE
})
@Retention(RetentionPolicy.SOURCE)
public @interface UnstartableReason {}
@@ -3800,23 +3800,20 @@
* Unstartable state with no root cause specified. E.g., data loader seeing missing pages but
* unclear about the cause. This corresponds to a generic alert window shown to the user when
* the user attempts to launch the app.
- * @hide
*/
public static final int UNSTARTABLE_REASON_UNKNOWN = 0;
/**
- * Unstartable state after hint from dataloader of issues with the transport layer.
- * This corresponds to an alert window shown to the user indicating network errors.
- * @hide
+ * Unstartable state due to connection issues that interrupt package loading.
+ * This corresponds to an alert window shown to the user indicating connection errors.
*/
- public static final int UNSTARTABLE_REASON_DATALOADER_TRANSPORT = 1;
+ public static final int UNSTARTABLE_REASON_CONNECTION_ERROR = 1;
/**
* Unstartable state after encountering storage limitations.
* This corresponds to an alert window indicating limited storage.
- * @hide
*/
- public static final int UNSTARTABLE_REASON_DATALOADER_STORAGE = 2;
+ public static final int UNSTARTABLE_REASON_INSUFFICIENT_STORAGE = 2;
/** {@hide} */
public int getUserId() {
diff --git a/core/java/android/hardware/biometrics/BiometricManager.java b/core/java/android/hardware/biometrics/BiometricManager.java
index 35ef53b..25c749b 100644
--- a/core/java/android/hardware/biometrics/BiometricManager.java
+++ b/core/java/android/hardware/biometrics/BiometricManager.java
@@ -35,6 +35,8 @@
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
+import java.util.ArrayList;
+import java.util.List;
/**
* A class that contains biometric utilities. For authentication, see {@link BiometricPrompt}.
@@ -199,13 +201,24 @@
}
/**
+ * @return A list of {@link SensorProperties}
+ * @hide
+ */
+ @TestApi
+ @NonNull
+ @RequiresPermission(TEST_BIOMETRIC)
+ public List<SensorProperties> getSensorProperties() {
+ return new ArrayList<>(); // TODO(169459906)
+ }
+
+ /**
* Retrieves a test session for BiometricManager/BiometricPrompt.
* @hide
*/
@TestApi
@NonNull
@RequiresPermission(TEST_BIOMETRIC)
- public BiometricTestSession getTestSession() {
+ public BiometricTestSession createTestSession(int sensorId) {
return null; // TODO(169459906)
}
diff --git a/core/java/android/hardware/biometrics/BiometricTestSession.java b/core/java/android/hardware/biometrics/BiometricTestSession.java
index 719efa8..4c7aa27 100644
--- a/core/java/android/hardware/biometrics/BiometricTestSession.java
+++ b/core/java/android/hardware/biometrics/BiometricTestSession.java
@@ -23,10 +23,7 @@
import android.annotation.TestApi;
import android.content.Context;
import android.os.RemoteException;
-import android.util.Log;
-
-import java.util.ArrayList;
-import java.util.List;
+import android.util.ArraySet;
/**
* Common set of interfaces to test biometric-related APIs, including {@link BiometricPrompt} and
@@ -35,37 +32,20 @@
*/
@TestApi
public class BiometricTestSession implements AutoCloseable {
-
- private static final String TAG = "TestManager";
-
private final Context mContext;
- private final ITestService mTestService;
+ private final ITestSession mTestSession;
+
+ // Keep track of users that were tested, which need to be cleaned up when finishing.
+ private final ArraySet<Integer> mTestedUsers;
/**
* @hide
*/
- public BiometricTestSession(@NonNull Context context, @NonNull ITestService testService) {
+ public BiometricTestSession(@NonNull Context context, @NonNull ITestSession testSession) {
mContext = context;
- mTestService = testService;
- }
-
- /**
- * @return A list of {@link SensorProperties}
- */
- @NonNull
- @RequiresPermission(TEST_BIOMETRIC)
- public List<SensorProperties> getSensorProperties() {
- try {
- final List<SensorPropertiesInternal> internalProps =
- mTestService.getSensorPropertiesInternal(mContext.getOpPackageName());
- final List<SensorProperties> props = new ArrayList<>();
- for (SensorPropertiesInternal internalProp : internalProps) {
- props.add(new SensorProperties(internalProp.sensorId, internalProp.sensorStrength));
- }
- return props;
- } catch (RemoteException e) {
- throw e.rethrowFromSystemServer();
- }
+ mTestSession = testSession;
+ mTestedUsers = new ArraySet<>();
+ enableTestHal(true);
}
/**
@@ -75,105 +55,100 @@
* secure pathways such as HAT/Keystore are not testable, since they depend on the TEE or its
* equivalent for the secret key.
*
- * @param sensorId Sensor that this command applies to.
* @param enableTestHal If true, enable testing with a fake HAL instead of the real HAL.
*/
@RequiresPermission(TEST_BIOMETRIC)
- public void enableTestHal(int sensorId, boolean enableTestHal) {
+ private void enableTestHal(boolean enableTestHal) {
try {
- mTestService.enableTestHal(sensorId, enableTestHal);
+ mTestSession.enableTestHal(enableTestHal);
} catch (RemoteException e) {
- Log.e(TAG, "Remote exception", e);
+ throw e.rethrowFromSystemServer();
}
}
/**
* Starts the enrollment process. This should generally be used when the test HAL is enabled.
*
- * @param sensorId Sensor that this command applies to.
* @param userId User that this command applies to.
*/
@RequiresPermission(TEST_BIOMETRIC)
- public void enrollStart(int sensorId, int userId) {
+ public void startEnroll(int userId) {
try {
- mTestService.enrollStart(sensorId, userId);
+ mTestedUsers.add(userId);
+ mTestSession.startEnroll(userId);
} catch (RemoteException e) {
- Log.e(TAG, "Remote exception", e);
+ throw e.rethrowFromSystemServer();
}
}
/**
* Finishes the enrollment process. Simulates the HAL's callback.
*
- * @param sensorId Sensor that this command applies to.
* @param userId User that this command applies to.
*/
@RequiresPermission(TEST_BIOMETRIC)
- public void enrollFinish(int sensorId, int userId) {
+ public void finishEnroll(int userId) {
try {
- mTestService.enrollFinish(sensorId, userId);
+ mTestedUsers.add(userId);
+ mTestSession.finishEnroll(userId);
} catch (RemoteException e) {
- Log.e(TAG, "Remote exception", e);
+ throw e.rethrowFromSystemServer();
}
}
/**
* Simulates a successful authentication, but does not provide a valid HAT.
*
- * @param sensorId Sensor that this command applies to.
* @param userId User that this command applies to.
*/
@RequiresPermission(TEST_BIOMETRIC)
- public void authenticateSuccess(int sensorId, int userId) {
+ public void acceptAuthentication(int userId) {
try {
- mTestService.authenticateSuccess(sensorId, userId);
+ mTestSession.acceptAuthentication(userId);
} catch (RemoteException e) {
- Log.e(TAG, "Remote exception", e);
+ throw e.rethrowFromSystemServer();
}
}
/**
* Simulates a rejected attempt.
*
- * @param sensorId Sensor that this command applies to.
* @param userId User that this command applies to.
*/
@RequiresPermission(TEST_BIOMETRIC)
- public void authenticateReject(int sensorId, int userId) {
+ public void rejectAuthentication(int userId) {
try {
- mTestService.authenticateReject(sensorId, userId);
+ mTestSession.rejectAuthentication(userId);
} catch (RemoteException e) {
- Log.e(TAG, "Remote exception", e);
+ throw e.rethrowFromSystemServer();
}
}
/**
* Simulates an acquired message from the HAL.
*
- * @param sensorId Sensor that this command applies to.
* @param userId User that this command applies to.
*/
@RequiresPermission(TEST_BIOMETRIC)
- public void notifyAcquired(int sensorId, int userId) {
+ public void notifyAcquired(int userId) {
try {
- mTestService.notifyAcquired(sensorId, userId);
+ mTestSession.notifyAcquired(userId);
} catch (RemoteException e) {
- Log.e(TAG, "Remote exception", e);
+ throw e.rethrowFromSystemServer();
}
}
/**
* Simulates an error message from the HAL.
*
- * @param sensorId Sensor that this command applies to.
* @param userId User that this command applies to.
*/
@RequiresPermission(TEST_BIOMETRIC)
- public void notifyError(int sensorId, int userId) {
+ public void notifyError(int userId) {
try {
- mTestService.notifyError(sensorId, userId);
+ mTestSession.notifyError(userId);
} catch (RemoteException e) {
- Log.e(TAG, "Remote exception", e);
+ throw e.rethrowFromSystemServer();
}
}
@@ -182,21 +157,24 @@
* that isn't known by both sides are deleted. This should generally be used when the test
* HAL is disabled (e.g. to clean up after a test).
*
- * @param sensorId Sensor that this command applies to.
* @param userId User that this command applies to.
*/
@RequiresPermission(TEST_BIOMETRIC)
- public void internalCleanup(int sensorId, int userId) {
+ public void cleanupInternalState(int userId) {
try {
- mTestService.internalCleanup(sensorId, userId);
+ mTestSession.cleanupInternalState(userId);
} catch (RemoteException e) {
- Log.e(TAG, "Remote exception", e);
+ throw e.rethrowFromSystemServer();
}
}
@Override
@RequiresPermission(TEST_BIOMETRIC)
public void close() {
+ for (int user : mTestedUsers) {
+ cleanupInternalState(user);
+ }
+ enableTestHal(false);
}
}
diff --git a/core/java/android/hardware/biometrics/ITestService.aidl b/core/java/android/hardware/biometrics/ITestSession.aidl
similarity index 75%
rename from core/java/android/hardware/biometrics/ITestService.aidl
rename to core/java/android/hardware/biometrics/ITestSession.aidl
index 6373132..5677f65 100644
--- a/core/java/android/hardware/biometrics/ITestService.aidl
+++ b/core/java/android/hardware/biometrics/ITestSession.aidl
@@ -21,37 +21,34 @@
* A test service for FingerprintManager and BiometricPrompt.
* @hide
*/
-interface ITestService {
- // Returns a list of sensor properties supported by the interface.
- List<SensorPropertiesInternal> getSensorPropertiesInternal(String opPackageName);
-
+interface ITestSession {
// Switches the specified sensor to use a test HAL. In this mode, the framework will not invoke
// any methods on the real HAL implementation. This allows the framework to test a substantial
// portion of the framework code that would otherwise require human interaction. Note that
// secure pathways such as HAT/Keystore are not testable, since they depend on the TEE or its
// equivalent for the secret key.
- void enableTestHal(int sensorId, boolean enableTestHal);
+ void enableTestHal(boolean enableTestHal);
// Starts the enrollment process. This should generally be used when the test HAL is enabled.
- void enrollStart(int sensorId, int userId);
+ void startEnroll(int userId);
// Finishes the enrollment process. Simulates the HAL's callback.
- void enrollFinish(int sensorId, int userId);
+ void finishEnroll(int userId);
// Simulates a successful authentication, but does not provide a valid HAT.
- void authenticateSuccess(int sensorId, int userId);
+ void acceptAuthentication(int userId);
// Simulates a rejected attempt.
- void authenticateReject(int sensorId, int userId);
+ void rejectAuthentication(int userId);
// Simulates an acquired message from the HAL.
- void notifyAcquired(int sensorId, int userId);
+ void notifyAcquired(int userId);
// Simulates an error message from the HAL.
- void notifyError(int sensorId, int userId);
+ void notifyError(int userId);
// Matches the framework's cached enrollments against the HAL's enrollments. Any enrollment
// that isn't known by both sides are deleted. This should generally be used when the test
// HAL is disabled (e.g. to clean up after a test).
- void internalCleanup(int sensorId, int userId);
+ void cleanupInternalState(int userId);
}
diff --git a/core/java/android/hardware/fingerprint/FingerprintManager.java b/core/java/android/hardware/fingerprint/FingerprintManager.java
index b35a68f..c5f8dac 100644
--- a/core/java/android/hardware/fingerprint/FingerprintManager.java
+++ b/core/java/android/hardware/fingerprint/FingerprintManager.java
@@ -39,6 +39,7 @@
import android.hardware.biometrics.BiometricPrompt;
import android.hardware.biometrics.BiometricTestSession;
import android.hardware.biometrics.IBiometricServiceLockoutResetCallback;
+import android.hardware.biometrics.SensorProperties;
import android.os.Binder;
import android.os.CancellationSignal;
import android.os.CancellationSignal.OnCancelListener;
@@ -97,6 +98,24 @@
private Fingerprint mRemovalFingerprint;
private Handler mHandler;
+
+ /**
+ * Retrieves a list of properties for all fingerprint sensors on the device.
+ * @hide
+ */
+ @TestApi
+ @NonNull
+ @RequiresPermission(TEST_BIOMETRIC)
+ public List<SensorProperties> getSensorProperties() {
+ final List<SensorProperties> properties = new ArrayList<>();
+ final List<FingerprintSensorPropertiesInternal> internalProperties
+ = getSensorPropertiesInternal();
+ for (FingerprintSensorPropertiesInternal internalProp : internalProperties) {
+ properties.add(FingerprintSensorProperties.from(internalProp));
+ }
+ return properties;
+ }
+
/**
* Retrieves a test session for FingerprintManager.
* @hide
@@ -104,10 +123,10 @@
@TestApi
@NonNull
@RequiresPermission(TEST_BIOMETRIC)
- public BiometricTestSession getTestSession() {
+ public BiometricTestSession createTestSession(int sensorId) {
try {
return new BiometricTestSession(mContext,
- mService.getTestService(mContext.getOpPackageName()));
+ mService.createTestSession(sensorId, mContext.getOpPackageName()));
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
@@ -878,21 +897,6 @@
}
/**
- * Retrieves a list of properties for all fingerprint sensors on the device.
- * @hide
- */
- @NonNull
- public List<FingerprintSensorProperties> getSensorProperties() {
- final List<FingerprintSensorProperties> properties = new ArrayList<>();
- final List<FingerprintSensorPropertiesInternal> internalProperties
- = getSensorPropertiesInternal();
- for (FingerprintSensorPropertiesInternal internalProp : internalProperties) {
- properties.add(FingerprintSensorProperties.from(internalProp));
- }
- return properties;
- }
-
- /**
* Get statically configured sensor properties.
* @hide
*/
diff --git a/core/java/android/hardware/fingerprint/IFingerprintService.aidl b/core/java/android/hardware/fingerprint/IFingerprintService.aidl
index e8ca590..cc086cf 100644
--- a/core/java/android/hardware/fingerprint/IFingerprintService.aidl
+++ b/core/java/android/hardware/fingerprint/IFingerprintService.aidl
@@ -17,7 +17,7 @@
import android.hardware.biometrics.IBiometricSensorReceiver;
import android.hardware.biometrics.IBiometricServiceLockoutResetCallback;
-import android.hardware.biometrics.ITestService;
+import android.hardware.biometrics.ITestSession;
import android.hardware.fingerprint.IFingerprintClientActiveCallback;
import android.hardware.fingerprint.IFingerprintServiceReceiver;
import android.hardware.fingerprint.IUdfpsOverlayController;
@@ -32,8 +32,8 @@
*/
interface IFingerprintService {
- // Retrieves a test service
- ITestService getTestService(String opPackageName);
+ // Creates a test session with the specified sensorId
+ ITestSession createTestSession(int sensorId, String opPackageName);
// Retrieve static sensor properties for all fingerprint sensors
List<FingerprintSensorPropertiesInternal> getSensorPropertiesInternal(String opPackageName);
diff --git a/core/java/android/os/connectivity/CellularBatteryStats.java b/core/java/android/os/connectivity/CellularBatteryStats.java
index 121fd33..fc17002 100644
--- a/core/java/android/os/connectivity/CellularBatteryStats.java
+++ b/core/java/android/os/connectivity/CellularBatteryStats.java
@@ -109,7 +109,7 @@
CellSignalStrength.getNumSignalStrengthLevels()));
mTxTimeMs = Arrays.copyOfRange(
txTimeMs, 0,
- Math.min(txTimeMs.length, ModemActivityInfo.TX_POWER_LEVELS));
+ Math.min(txTimeMs.length, ModemActivityInfo.getNumTxPowerLevels()));
mMonitoredRailChargeConsumedMaMs = monitoredRailChargeConsumedMaMs;
}
diff --git a/core/java/android/service/wallpaper/WallpaperService.java b/core/java/android/service/wallpaper/WallpaperService.java
index 0f46ffc..4d1337b 100644
--- a/core/java/android/service/wallpaper/WallpaperService.java
+++ b/core/java/android/service/wallpaper/WallpaperService.java
@@ -227,9 +227,6 @@
SurfaceControl mSurfaceControl = new SurfaceControl();
- // Unused relayout out-param
- SurfaceControl mTmpSurfaceControl = new SurfaceControl();
-
final BaseSurfaceHolder mSurfaceHolder = new BaseSurfaceHolder() {
{
mRequestedFormat = PixelFormat.RGBX_8888;
@@ -905,7 +902,7 @@
final int relayoutResult = mSession.relayout(
mWindow, mLayout, mWidth, mHeight,
View.VISIBLE, 0, -1, mWinFrames, mMergedConfiguration, mSurfaceControl,
- mInsetsState, mTempControls, mSurfaceSize, mTmpSurfaceControl);
+ mInsetsState, mTempControls, mSurfaceSize);
if (mSurfaceControl.isValid()) {
mSurfaceHolder.mSurface.copyFrom(mSurfaceControl);
}
diff --git a/core/java/android/view/IWindowSession.aidl b/core/java/android/view/IWindowSession.aidl
index 69a5faf..910fd90 100644
--- a/core/java/android/view/IWindowSession.aidl
+++ b/core/java/android/view/IWindowSession.aidl
@@ -98,9 +98,6 @@
* @param outSurface Object in which is placed the new display surface.
* @param insetsState The current insets state in the system.
* @param outSurfaceSize The width and height of the surface control
- * @param outBlastSurfaceControl A BLAST SurfaceControl allocated by the WindowManager
- * the SurfaceControl willl be managed by the client side, but the WindowManager
- * may use it as a deferTransaction barrier.
*
* @return int Result flags: {@link WindowManagerGlobal#RELAYOUT_SHOW_FOCUS},
* {@link WindowManagerGlobal#RELAYOUT_FIRST_TIME}.
@@ -110,7 +107,7 @@
int flags, long frameNumber, out ClientWindowFrames outFrames,
out MergedConfiguration outMergedConfiguration, out SurfaceControl outSurfaceControl,
out InsetsState insetsState, out InsetsSourceControl[] activeControls,
- out Point outSurfaceSize, out SurfaceControl outBlastSurfaceControl);
+ out Point outSurfaceSize);
/*
* Notify the window manager that an application is relaunching and
diff --git a/core/java/android/view/RemoteAccessibilityController.java b/core/java/android/view/RemoteAccessibilityController.java
new file mode 100644
index 0000000..bc0fab1b
--- /dev/null
+++ b/core/java/android/view/RemoteAccessibilityController.java
@@ -0,0 +1,168 @@
+/*
+ * 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.
+ */
+
+package android.view;
+
+import android.graphics.Matrix;
+import android.os.Handler;
+import android.os.IBinder;
+import android.os.Looper;
+import android.os.RemoteException;
+import android.util.Log;
+import android.view.accessibility.IAccessibilityEmbeddedConnection;
+
+class RemoteAccessibilityController {
+ private static final String TAG = "RemoteAccessibilityController";
+ private int mHostId;
+ private RemoteAccessibilityEmbeddedConnection mConnectionWrapper;
+ private Matrix mScreenMatrixForEmbeddedHierarchy = new Matrix();
+ private final float[] mMatrixValues = new float[9];
+ private View mHostView;
+
+ RemoteAccessibilityController(View v) {
+ mHostView = v;
+ }
+
+ private void runOnUiThread(Runnable runnable) {
+ final Handler h = mHostView.getHandler();
+ if (h != null && h.getLooper() != Looper.myLooper()) {
+ h.post(runnable);
+ } else {
+ runnable.run();
+ }
+ }
+
+ void assosciateHierarchy(IAccessibilityEmbeddedConnection connection,
+ IBinder leashToken, int hostId) {
+ mHostId = hostId;
+
+ try {
+ leashToken = connection.associateEmbeddedHierarchy(
+ leashToken, mHostId);
+ setRemoteAccessibilityEmbeddedConnection(connection, leashToken);
+ } catch (RemoteException e) {
+ Log.d(TAG, "Error in associateEmbeddedHierarchy " + e);
+ }
+ }
+
+ void disassosciateHierarchy() {
+ setRemoteAccessibilityEmbeddedConnection(null, null);
+ }
+
+ boolean alreadyAssociated(IAccessibilityEmbeddedConnection connection) {
+ if (mConnectionWrapper == null) {
+ return false;
+ }
+ return mConnectionWrapper.mConnection.equals(connection);
+ }
+
+ boolean connected() {
+ return mConnectionWrapper != null;
+ }
+
+ IBinder getLeashToken() {
+ return mConnectionWrapper.getLeashToken();
+ }
+
+ /**
+ * Wrapper of accessibility embedded connection for embedded view hierarchy.
+ */
+ private final class RemoteAccessibilityEmbeddedConnection implements IBinder.DeathRecipient {
+ private final IAccessibilityEmbeddedConnection mConnection;
+ private final IBinder mLeashToken;
+
+ RemoteAccessibilityEmbeddedConnection(IAccessibilityEmbeddedConnection connection,
+ IBinder leashToken) {
+ mConnection = connection;
+ mLeashToken = leashToken;
+ }
+
+ IAccessibilityEmbeddedConnection getConnection() {
+ return mConnection;
+ }
+
+ IBinder getLeashToken() {
+ return mLeashToken;
+ }
+
+ void linkToDeath() throws RemoteException {
+ mConnection.asBinder().linkToDeath(this, 0);
+ }
+
+ void unlinkToDeath() {
+ mConnection.asBinder().unlinkToDeath(this, 0);
+ }
+
+ @Override
+ public void binderDied() {
+ unlinkToDeath();
+ runOnUiThread(() -> {
+ if (mConnectionWrapper == this) {
+ mConnectionWrapper = null;
+ }
+ });
+ }
+ }
+
+ private void setRemoteAccessibilityEmbeddedConnection(
+ IAccessibilityEmbeddedConnection connection, IBinder leashToken) {
+ try {
+ if (mConnectionWrapper != null) {
+ mConnectionWrapper.getConnection()
+ .disassociateEmbeddedHierarchy();
+ mConnectionWrapper.unlinkToDeath();
+ mConnectionWrapper = null;
+ }
+ if (connection != null && leashToken != null) {
+ mConnectionWrapper =
+ new RemoteAccessibilityEmbeddedConnection(connection, leashToken);
+ mConnectionWrapper.linkToDeath();
+ }
+ } catch (RemoteException e) {
+ Log.d(TAG, "Error while setRemoteEmbeddedConnection " + e);
+ }
+ }
+
+ private RemoteAccessibilityEmbeddedConnection getRemoteAccessibilityEmbeddedConnection() {
+ return mConnectionWrapper;
+ }
+
+ void setScreenMatrix(Matrix m) {
+ // If the screen matrix is identity or doesn't change, do nothing.
+ if (m.isIdentity() || m.equals(mScreenMatrixForEmbeddedHierarchy)) {
+ return;
+ }
+
+ try {
+ final RemoteAccessibilityEmbeddedConnection wrapper =
+ getRemoteAccessibilityEmbeddedConnection();
+ if (wrapper == null) {
+ return;
+ }
+ m.getValues(mMatrixValues);
+ wrapper.getConnection().setScreenMatrix(mMatrixValues);
+ mScreenMatrixForEmbeddedHierarchy.set(m);
+ } catch (RemoteException e) {
+ Log.d(TAG, "Error while setScreenMatrix " + e);
+ }
+ }
+
+
+
+
+
+
+}
diff --git a/core/java/android/view/SurfaceView.java b/core/java/android/view/SurfaceView.java
index 78c71b8..7b6a4f8 100644
--- a/core/java/android/view/SurfaceView.java
+++ b/core/java/android/view/SurfaceView.java
@@ -41,7 +41,6 @@
import android.os.Handler;
import android.os.IBinder;
import android.os.Looper;
-import android.os.RemoteException;
import android.os.SystemClock;
import android.provider.Settings;
import android.util.AttributeSet;
@@ -225,13 +224,12 @@
private SurfaceControl.Transaction mRtTransaction = new SurfaceControl.Transaction();
private SurfaceControl.Transaction mTmpTransaction = new SurfaceControl.Transaction();
- private int mParentSurfaceGenerationId;
+ private int mParentSurfaceSequenceId;
- private RemoteAccessibilityEmbeddedConnection mRemoteAccessibilityEmbeddedConnection;
+ private RemoteAccessibilityController mRemoteAccessibilityController =
+ new RemoteAccessibilityController(this);
- private final Matrix mScreenMatrixForEmbeddedHierarchy = new Matrix();
private final Matrix mTmpMatrix = new Matrix();
- private final float[] mMatrixValues = new float[9];
SurfaceControlViewHost.SurfacePackage mSurfacePackage;
@@ -467,7 +465,7 @@
Transaction t = new SurfaceControl.Transaction();
t.setAlpha(mSurfaceControl, alpha);
t.deferTransactionUntil(mSurfaceControl,
- viewRoot.getRenderSurfaceControl(), frame);
+ viewRoot.getSurfaceControl(), frame);
t.apply();
}
}
@@ -827,7 +825,7 @@
final SurfaceControl.Transaction t = new SurfaceControl.Transaction();
updateRelativeZ(t);
t.deferTransactionUntil(mSurfaceControl,
- viewRoot.getRenderSurfaceControl(), frame);
+ viewRoot.getSurfaceControl(), frame);
t.apply();
}
}
@@ -927,6 +925,103 @@
}
}
+ private boolean performSurfaceTransaction(ViewRootImpl viewRoot, Translator translator,
+ boolean creating, boolean sizeChanged, boolean needBLASTSync) {
+ boolean realSizeChanged = false;
+
+ mSurfaceLock.lock();
+ try {
+ mDrawingStopped = !mVisible;
+
+ if (DEBUG) Log.i(TAG, System.identityHashCode(this) + " "
+ + "Cur surface: " + mSurface);
+
+ // If we are creating the surface control or the parent surface has not
+ // changed, then set relative z. Otherwise allow the parent
+ // SurfaceChangedCallback to update the relative z. This is needed so that
+ // we do not change the relative z before the server is ready to swap the
+ // parent surface.
+ if (creating || (mParentSurfaceSequenceId == viewRoot.getSurfaceSequenceId())) {
+ updateRelativeZ(mTmpTransaction);
+ }
+ mParentSurfaceSequenceId = viewRoot.getSurfaceSequenceId();
+
+ if (mViewVisibility) {
+ mTmpTransaction.show(mSurfaceControl);
+ } else {
+ mTmpTransaction.hide(mSurfaceControl);
+ }
+
+ if (mSurfacePackage != null) {
+ reparentSurfacePackage(mTmpTransaction, mSurfacePackage);
+ }
+
+ updateBackgroundVisibility(mTmpTransaction);
+ updateBackgroundColor(mTmpTransaction);
+ if (mUseAlpha) {
+ float alpha = getFixedAlpha();
+ mTmpTransaction.setAlpha(mSurfaceControl, alpha);
+ mSurfaceAlpha = alpha;
+ }
+
+ // While creating the surface, we will set it's initial
+ // geometry. Outside of that though, we should generally
+ // leave it to the RenderThread.
+ //
+ // There is one more case when the buffer size changes we aren't yet
+ // prepared to sync (as even following the transaction applying
+ // we still need to latch a buffer).
+ // b/28866173
+ if (sizeChanged || creating || !mRtHandlingPositionUpdates) {
+ onSetSurfacePositionAndScaleRT(mTmpTransaction, mSurfaceControl,
+ mScreenRect.left, /*positionLeft*/
+ mScreenRect.top /*positionTop*/ ,
+ mScreenRect.width() / (float) mSurfaceWidth /*postScaleX*/,
+ mScreenRect.height() / (float) mSurfaceHeight /*postScaleY*/);
+
+ // Set a window crop when creating the surface or changing its size to
+ // crop the buffer to the surface size since the buffer producer may
+ // use SCALING_MODE_SCALE and submit a larger size than the surface
+ // size.
+ if (mClipSurfaceToBounds && mClipBounds != null) {
+ mTmpTransaction.setWindowCrop(mSurfaceControl, mClipBounds);
+ } else {
+ mTmpTransaction.setWindowCrop(mSurfaceControl, mSurfaceWidth,
+ mSurfaceHeight);
+ }
+ } else if (needBLASTSync) {
+ viewRoot.setUseBLASTSyncTransaction();
+ }
+ mTmpTransaction.setCornerRadius(mSurfaceControl, mCornerRadius);
+ if (sizeChanged && !creating) {
+ setBufferSize(mTmpTransaction);
+ }
+
+ mTmpTransaction.apply();
+ updateEmbeddedAccessibilityMatrix();
+
+ mSurfaceFrame.left = 0;
+ mSurfaceFrame.top = 0;
+ if (translator == null) {
+ mSurfaceFrame.right = mSurfaceWidth;
+ mSurfaceFrame.bottom = mSurfaceHeight;
+ } else {
+ float appInvertedScale = translator.applicationInvertedScale;
+ mSurfaceFrame.right = (int) (mSurfaceWidth * appInvertedScale + 0.5f);
+ mSurfaceFrame.bottom = (int) (mSurfaceHeight * appInvertedScale + 0.5f);
+ }
+ final int surfaceWidth = mSurfaceFrame.right;
+ final int surfaceHeight = mSurfaceFrame.bottom;
+ realSizeChanged = mLastSurfaceWidth != surfaceWidth
+ || mLastSurfaceHeight != surfaceHeight;
+ mLastSurfaceWidth = surfaceWidth;
+ mLastSurfaceHeight = surfaceHeight;
+ } finally {
+ mSurfaceLock.unlock();
+ }
+ return realSizeChanged;
+ }
+
/** @hide */
protected void updateSurface() {
if (!mHaveFrame) {
@@ -965,7 +1060,6 @@
&& mRequestedVisible;
final boolean sizeChanged = mSurfaceWidth != myWidth || mSurfaceHeight != myHeight;
final boolean windowVisibleChanged = mWindowVisibility != mLastWindowVisibility;
- boolean redrawNeeded = false;
getLocationInSurface(mLocation);
final boolean positionChanged = mWindowSpaceLeft != mLocation[0]
|| mWindowSpaceTop != mLocation[1];
@@ -988,7 +1082,7 @@
+ " top=" + (mWindowSpaceTop != mLocation[1]));
try {
- final boolean visible = mVisible = mRequestedVisible;
+ mVisible = mRequestedVisible;
mWindowSpaceLeft = mLocation[0];
mWindowSpaceTop = mLocation[1];
mSurfaceWidth = myWidth;
@@ -1014,119 +1108,26 @@
return;
}
- boolean realSizeChanged = false;
-
- mSurfaceLock.lock();
- try {
- mDrawingStopped = !visible;
-
- if (DEBUG) Log.i(TAG, System.identityHashCode(this) + " "
- + "Cur surface: " + mSurface);
-
- // If we are creating the surface control or the parent surface has not
- // changed, then set relative z. Otherwise allow the parent
- // SurfaceChangedCallback to update the relative z. This is needed so that
- // we do not change the relative z before the server is ready to swap the
- // parent surface.
- if (creating || (mParentSurfaceGenerationId
- == viewRoot.mSurface.getGenerationId())) {
- updateRelativeZ(mTmpTransaction);
- }
- mParentSurfaceGenerationId = viewRoot.mSurface.getGenerationId();
-
- if (mViewVisibility) {
- mTmpTransaction.show(mSurfaceControl);
- } else {
- mTmpTransaction.hide(mSurfaceControl);
- }
-
- if (mSurfacePackage != null) {
- reparentSurfacePackage(mTmpTransaction, mSurfacePackage);
- }
-
- updateBackgroundVisibility(mTmpTransaction);
- updateBackgroundColor(mTmpTransaction);
- if (mUseAlpha) {
- mTmpTransaction.setAlpha(mSurfaceControl, alpha);
- mSurfaceAlpha = alpha;
- }
-
- // While creating the surface, we will set it's initial
- // geometry. Outside of that though, we should generally
- // leave it to the RenderThread.
- //
- // There is one more case when the buffer size changes we aren't yet
- // prepared to sync (as even following the transaction applying
- // we still need to latch a buffer).
- // b/28866173
- if (sizeChanged || creating || !mRtHandlingPositionUpdates) {
- onSetSurfacePositionAndScaleRT(mTmpTransaction, mSurfaceControl,
- mScreenRect.left, /*positionLeft*/
- mScreenRect.top /*positionTop*/ ,
- mScreenRect.width() / (float) mSurfaceWidth /*postScaleX*/,
- mScreenRect.height() / (float) mSurfaceHeight /*postScaleY*/);
-
- // Set a window crop when creating the surface or changing its size to
- // crop the buffer to the surface size since the buffer producer may
- // use SCALING_MODE_SCALE and submit a larger size than the surface
- // size.
- if (mClipSurfaceToBounds && mClipBounds != null) {
- mTmpTransaction.setWindowCrop(mSurfaceControl, mClipBounds);
- } else {
- mTmpTransaction.setWindowCrop(mSurfaceControl, mSurfaceWidth,
- mSurfaceHeight);
- }
- } else if ((layoutSizeChanged || positionChanged || visibleChanged) &&
- viewRoot.useBLAST()) {
- viewRoot.setUseBLASTSyncTransaction();
- }
- mTmpTransaction.setCornerRadius(mSurfaceControl, mCornerRadius);
- if (sizeChanged && !creating) {
- setBufferSize(mTmpTransaction);
- }
-
- mTmpTransaction.apply();
- updateScreenMatrixForEmbeddedHierarchy();
-
- if (sizeChanged || creating) {
- redrawNeeded = true;
- }
-
- mSurfaceFrame.left = 0;
- mSurfaceFrame.top = 0;
- if (translator == null) {
- mSurfaceFrame.right = mSurfaceWidth;
- mSurfaceFrame.bottom = mSurfaceHeight;
- } else {
- float appInvertedScale = translator.applicationInvertedScale;
- mSurfaceFrame.right = (int) (mSurfaceWidth * appInvertedScale + 0.5f);
- mSurfaceFrame.bottom = (int) (mSurfaceHeight * appInvertedScale + 0.5f);
- }
-
- final int surfaceWidth = mSurfaceFrame.right;
- final int surfaceHeight = mSurfaceFrame.bottom;
- realSizeChanged = mLastSurfaceWidth != surfaceWidth
- || mLastSurfaceHeight != surfaceHeight;
- mLastSurfaceWidth = surfaceWidth;
- mLastSurfaceHeight = surfaceHeight;
- } finally {
- mSurfaceLock.unlock();
- }
+ final boolean needBLASTSync =
+ (layoutSizeChanged || positionChanged || visibleChanged) &&
+ viewRoot.useBLAST();
+ final boolean realSizeChanged = performSurfaceTransaction(viewRoot,
+ translator, creating, sizeChanged, needBLASTSync);
+ final boolean redrawNeeded = sizeChanged || creating ||
+ (mVisible && !mDrawFinished);
try {
- redrawNeeded |= visible && !mDrawFinished;
-
SurfaceHolder.Callback[] callbacks = null;
final boolean surfaceChanged = creating;
- if (mSurfaceCreated && (surfaceChanged || (!visible && visibleChanged))) {
+ if (mSurfaceCreated && (surfaceChanged || (!mVisible && visibleChanged))) {
mSurfaceCreated = false;
notifySurfaceDestroyed();
}
copySurface(creating /* surfaceControlCreated */, sizeChanged);
- if (visible && mSurface.isValid()) {
+ if (mVisible && mSurface.isValid()) {
if (!mSurfaceCreated && (surfaceChanged || visibleChanged)) {
mSurfaceCreated = true;
mIsCreating = true;
@@ -1352,7 +1353,7 @@
Rect position, long frameNumber) {
final ViewRootImpl viewRoot = getViewRootImpl();
if (frameNumber > 0 && viewRoot != null && !viewRoot.useBLAST()) {
- t.deferTransactionUntil(surface, viewRoot.getRenderSurfaceControl(),
+ t.deferTransactionUntil(surface, viewRoot.getSurfaceControl(),
frameNumber);
}
@@ -1470,7 +1471,7 @@
} else {
if (frameNumber > 0 && viewRoot != null && viewRoot.mSurface.isValid()) {
mRtTransaction.deferTransactionUntil(mSurfaceControl,
- viewRoot.getRenderSurfaceControl(), frameNumber);
+ viewRoot.getSurfaceControl(), frameNumber);
}
mRtTransaction.hide(mSurfaceControl);
if (mRtReleaseSurfaces) {
@@ -1754,7 +1755,7 @@
@Override
public void surfaceDestroyed() {
setWindowStopped(true);
- setRemoteAccessibilityEmbeddedConnection(null, null);
+ mRemoteAccessibilityController.disassosciateHierarchy();
}
/**
@@ -1834,14 +1835,12 @@
@Override
public void onInitializeAccessibilityNodeInfoInternal(AccessibilityNodeInfo info) {
super.onInitializeAccessibilityNodeInfoInternal(info);
- final RemoteAccessibilityEmbeddedConnection wrapper =
- getRemoteAccessibilityEmbeddedConnection();
- if (wrapper == null) {
+ if (!mRemoteAccessibilityController.connected()) {
return;
}
// Add a leashed child when this SurfaceView embeds another view hierarchy. Getting this
// leashed child would return the root node in the embedded hierarchy
- info.addChild(wrapper.getLeashToken());
+ info.addChild(mRemoteAccessibilityController.getLeashToken());
}
@Override
@@ -1850,7 +1849,7 @@
// If developers explicitly set the important mode for it, don't change the mode.
// Only change the mode to important when this SurfaceView isn't explicitly set and has
// an embedded hierarchy.
- if (mRemoteAccessibilityEmbeddedConnection == null
+ if (!mRemoteAccessibilityController.connected()
|| mode != IMPORTANT_FOR_ACCESSIBILITY_AUTO) {
return mode;
}
@@ -1859,74 +1858,13 @@
private void initEmbeddedHierarchyForAccessibility(SurfaceControlViewHost.SurfacePackage p) {
final IAccessibilityEmbeddedConnection connection = p.getAccessibilityEmbeddedConnection();
- final RemoteAccessibilityEmbeddedConnection wrapper =
- getRemoteAccessibilityEmbeddedConnection();
-
- // Do nothing if package is embedding the same view hierarchy.
- if (wrapper != null && wrapper.getConnection().equals(connection)) {
+ if (mRemoteAccessibilityController.alreadyAssociated(connection)) {
return;
}
+ mRemoteAccessibilityController.assosciateHierarchy(connection,
+ getViewRootImpl().mLeashToken, getAccessibilityViewId());
- // If this SurfaceView embeds a different view hierarchy, unlink the previous one first.
- setRemoteAccessibilityEmbeddedConnection(null, null);
-
- try {
- final IBinder leashToken = connection.associateEmbeddedHierarchy(
- getViewRootImpl().mLeashToken, getAccessibilityViewId());
- setRemoteAccessibilityEmbeddedConnection(connection, leashToken);
- } catch (RemoteException e) {
- Log.d(TAG, "Error while associateEmbeddedHierarchy " + e);
- }
- updateScreenMatrixForEmbeddedHierarchy();
- }
-
- private void setRemoteAccessibilityEmbeddedConnection(
- IAccessibilityEmbeddedConnection connection, IBinder leashToken) {
- try {
- if (mRemoteAccessibilityEmbeddedConnection != null) {
- mRemoteAccessibilityEmbeddedConnection.getConnection()
- .disassociateEmbeddedHierarchy();
- mRemoteAccessibilityEmbeddedConnection.unlinkToDeath();
- mRemoteAccessibilityEmbeddedConnection = null;
- }
- if (connection != null && leashToken != null) {
- mRemoteAccessibilityEmbeddedConnection =
- new RemoteAccessibilityEmbeddedConnection(connection, leashToken);
- mRemoteAccessibilityEmbeddedConnection.linkToDeath();
- }
- } catch (RemoteException e) {
- Log.d(TAG, "Error while setRemoteEmbeddedConnection " + e);
- }
- }
-
- private RemoteAccessibilityEmbeddedConnection getRemoteAccessibilityEmbeddedConnection() {
- return mRemoteAccessibilityEmbeddedConnection;
- }
-
- private void updateScreenMatrixForEmbeddedHierarchy() {
- getBoundsOnScreen(mTmpRect);
- mTmpMatrix.reset();
- mTmpMatrix.setTranslate(mTmpRect.left, mTmpRect.top);
- mTmpMatrix.postScale(mScreenRect.width() / (float) mSurfaceWidth,
- mScreenRect.height() / (float) mSurfaceHeight);
-
- // If the screen matrix is identity or doesn't change, do nothing.
- if (mTmpMatrix.isIdentity() || mTmpMatrix.equals(mScreenMatrixForEmbeddedHierarchy)) {
- return;
- }
-
- try {
- final RemoteAccessibilityEmbeddedConnection wrapper =
- getRemoteAccessibilityEmbeddedConnection();
- if (wrapper == null) {
- return;
- }
- mTmpMatrix.getValues(mMatrixValues);
- wrapper.getConnection().setScreenMatrix(mMatrixValues);
- mScreenMatrixForEmbeddedHierarchy.set(mTmpMatrix);
- } catch (RemoteException e) {
- Log.d(TAG, "Error while setScreenMatrix " + e);
- }
+ updateEmbeddedAccessibilityMatrix();
}
private void notifySurfaceDestroyed() {
@@ -1954,6 +1892,18 @@
}
}
+ void updateEmbeddedAccessibilityMatrix() {
+ if (!mRemoteAccessibilityController.connected()) {
+ return;
+ }
+ getBoundsOnScreen(mTmpRect);
+ mTmpMatrix.reset();
+ mTmpMatrix.setTranslate(mTmpRect.left, mTmpRect.top);
+ mTmpMatrix.postScale(mScreenRect.width() / (float) mSurfaceWidth,
+ mScreenRect.height() / (float) mSurfaceHeight);
+ mRemoteAccessibilityController.setScreenMatrix(mTmpMatrix);
+ }
+
@Override
protected void onFocusChanged(boolean gainFocus, @FocusDirection int direction,
@Nullable Rect previouslyFocusedRect) {
@@ -1970,44 +1920,4 @@
+ "Exception requesting focus on embedded window", e);
}
}
-
- /**
- * Wrapper of accessibility embedded connection for embedded view hierarchy.
- */
- private final class RemoteAccessibilityEmbeddedConnection implements IBinder.DeathRecipient {
- private final IAccessibilityEmbeddedConnection mConnection;
- private final IBinder mLeashToken;
-
- RemoteAccessibilityEmbeddedConnection(IAccessibilityEmbeddedConnection connection,
- IBinder leashToken) {
- mConnection = connection;
- mLeashToken = leashToken;
- }
-
- IAccessibilityEmbeddedConnection getConnection() {
- return mConnection;
- }
-
- IBinder getLeashToken() {
- return mLeashToken;
- }
-
- void linkToDeath() throws RemoteException {
- mConnection.asBinder().linkToDeath(this, 0);
- }
-
- void unlinkToDeath() {
- mConnection.asBinder().unlinkToDeath(this, 0);
- }
-
- @Override
- public void binderDied() {
- unlinkToDeath();
- runOnUiThread(() -> {
- if (mRemoteAccessibilityEmbeddedConnection == this) {
- mRemoteAccessibilityEmbeddedConnection = null;
- }
- });
- }
- }
}
diff --git a/core/java/android/view/SyncRtSurfaceTransactionApplier.java b/core/java/android/view/SyncRtSurfaceTransactionApplier.java
index 062285f..bce78b5 100644
--- a/core/java/android/view/SyncRtSurfaceTransactionApplier.java
+++ b/core/java/android/view/SyncRtSurfaceTransactionApplier.java
@@ -60,7 +60,7 @@
if (mTargetViewRootImpl == null) {
return;
}
- mTargetSc = mTargetViewRootImpl.getRenderSurfaceControl();
+ mTargetSc = mTargetViewRootImpl.getSurfaceControl();
mTargetViewRootImpl.registerRtFrameCallback(frame -> {
if (mTargetSc == null || !mTargetSc.isValid()) {
return;
diff --git a/core/java/android/view/ViewRootImpl.java b/core/java/android/view/ViewRootImpl.java
index e00ff7e..5235740 100644
--- a/core/java/android/view/ViewRootImpl.java
+++ b/core/java/android/view/ViewRootImpl.java
@@ -105,6 +105,7 @@
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.FrameInfo;
+import android.graphics.HardwareRenderer;
import android.graphics.HardwareRenderer.FrameDrawingCallback;
import android.graphics.Insets;
import android.graphics.Matrix;
@@ -519,7 +520,6 @@
@UnsupportedAppUsage
public final Surface mSurface = new Surface();
private final SurfaceControl mSurfaceControl = new SurfaceControl();
- private SurfaceControl mBlastSurfaceControl = new SurfaceControl();
private BLASTBufferQueue mBlastBufferQueue;
@@ -702,6 +702,11 @@
private HashSet<ScrollCaptureCallback> mRootScrollCaptureCallbacks;
+ /**
+ * Increment this value when the surface has been replaced.
+ */
+ private int mSurfaceSequenceId = 0;
+
private String mTag = TAG;
public ViewRootImpl(Context context, Display display) {
@@ -1808,7 +1813,7 @@
mBoundsLayer = new SurfaceControl.Builder(mSurfaceSession)
.setContainerLayer()
.setName("Bounds for - " + getTitle().toString())
- .setParent(getRenderSurfaceControl())
+ .setParent(getSurfaceControl())
.setCallsite("ViewRootImpl.getBoundsLayer")
.build();
setBoundsLayerCrop(mTransaction);
@@ -1818,22 +1823,19 @@
}
Surface getOrCreateBLASTSurface(int width, int height) {
- if (mSurfaceControl == null
- || !mSurfaceControl.isValid()
- || mBlastSurfaceControl == null
- || !mBlastSurfaceControl.isValid()) {
+ if (!mSurfaceControl.isValid()) {
return null;
}
Surface ret = null;
if (mBlastBufferQueue == null) {
mBlastBufferQueue = new BLASTBufferQueue(mTag,
- mBlastSurfaceControl, width, height, mEnableTripleBuffering);
+ mSurfaceControl, width, height, mEnableTripleBuffering);
// We only return the Surface the first time, as otherwise
// it hasn't changed and there is no need to update.
ret = mBlastBufferQueue.createSurface();
} else {
- mBlastBufferQueue.update(mBlastSurfaceControl, width, height);
+ mBlastBufferQueue.update(mSurfaceControl, width, height);
}
return ret;
@@ -1855,7 +1857,7 @@
private boolean updateBoundsLayer(SurfaceControl.Transaction t) {
if (mBoundsLayer != null) {
setBoundsLayerCrop(t);
- t.deferTransactionUntil(mBoundsLayer, getRenderSurfaceControl(),
+ t.deferTransactionUntil(mBoundsLayer, getSurfaceControl(),
mSurface.getNextFrameNumber());
return true;
}
@@ -1864,7 +1866,7 @@
private void prepareSurfaces(boolean sizeChanged) {
final SurfaceControl.Transaction t = mTransaction;
- final SurfaceControl sc = getRenderSurfaceControl();
+ final SurfaceControl sc = getSurfaceControl();
if (!sc.isValid()) return;
boolean applyTransaction = updateBoundsLayer(t);
@@ -1885,7 +1887,6 @@
mSurface.release();
mSurfaceControl.release();
- mBlastSurfaceControl.release();
// We should probably add an explicit dispose.
mBlastBufferQueue = null;
}
@@ -2613,7 +2614,7 @@
boolean surfaceSizeChanged = false;
boolean surfaceCreated = false;
boolean surfaceDestroyed = false;
- /* True if surface generation id changes. */
+ // True if surface generation id changes or relayout result is RELAYOUT_RES_SURFACE_CHANGED.
boolean surfaceReplaced = false;
final boolean windowAttributesChanged = mWindowAttributesChanged;
@@ -2708,6 +2709,7 @@
updateColorModeIfNeeded(lp.getColorMode());
surfaceCreated = !hadSurface && mSurface.isValid();
surfaceDestroyed = hadSurface && !mSurface.isValid();
+
// When using Blast, the surface generation id may not change when there's a new
// SurfaceControl. In that case, we also check relayout flag
// RELAYOUT_RES_SURFACE_CHANGED since it should indicate that WMS created a new
@@ -2716,6 +2718,9 @@
|| (relayoutResult & RELAYOUT_RES_SURFACE_CHANGED)
== RELAYOUT_RES_SURFACE_CHANGED)
&& mSurface.isValid();
+ if (surfaceReplaced) {
+ mSurfaceSequenceId++;
+ }
if (cutoutChanged) {
mAttachInfo.mDisplayCutout.set(mPendingDisplayCutout);
@@ -3815,6 +3820,82 @@
}
}
+ /**
+ * The callback will run on the render thread.
+ */
+ private HardwareRenderer.FrameCompleteCallback createFrameCompleteCallback(Handler handler,
+ boolean reportNextDraw, ArrayList<Runnable> commitCallbacks) {
+ return frameNr -> {
+ // Use a new transaction here since mRtBLASTSyncTransaction can only be accessed by
+ // the render thread and mSurfaceChangedTransaction can only be accessed by the UI
+ // thread. The temporary transaction is used so mRtBLASTSyncTransaction can be merged
+ // with mSurfaceChangedTransaction without synchronization issues.
+ final Transaction t = new Transaction();
+ finishBLASTSyncOnRT(!mSendNextFrameToWm, t);
+ handler.postAtFrontOfQueue(() -> {
+ mSurfaceChangedTransaction.merge(t);
+ if (reportNextDraw) {
+ // TODO: Use the frame number
+ pendingDrawFinished();
+ }
+ if (commitCallbacks != null) {
+ for (int i = 0; i < commitCallbacks.size(); i++) {
+ commitCallbacks.get(i).run();
+ }
+ }
+ });
+ };
+ }
+
+ private boolean addFrameCompleteCallbackIfNeeded() {
+ if (mAttachInfo.mThreadedRenderer == null || !mAttachInfo.mThreadedRenderer.isEnabled()) {
+ return false;
+ }
+
+ ArrayList<Runnable> commitCallbacks = mAttachInfo.mTreeObserver
+ .captureFrameCommitCallbacks();
+ final boolean needFrameCompleteCallback =
+ mNextDrawUseBLASTSyncTransaction || mReportNextDraw
+ || (commitCallbacks != null && commitCallbacks.size() > 0);
+ if (needFrameCompleteCallback) {
+ mAttachInfo.mThreadedRenderer.setFrameCompleteCallback(
+ createFrameCompleteCallback(mAttachInfo.mHandler, mReportNextDraw,
+ commitCallbacks));
+ return true;
+ }
+ return false;
+ }
+
+ /**
+ * The callback will run on a worker thread pool from the render thread.
+ */
+ private HardwareRenderer.FrameDrawingCallback createFrameDrawingCallback() {
+ return frame -> {
+ mRtNextFrameReportedConsumeWithBlast = true;
+ if (mBlastBufferQueue != null) {
+ // We don't need to synchronize mRtBLASTSyncTransaction here since it's not
+ // being modified and only sent to BlastBufferQueue.
+ mBlastBufferQueue.setNextTransaction(mRtBLASTSyncTransaction);
+ }
+ };
+ }
+
+ private void addFrameCallbackIfNeeded() {
+ if (!mNextDrawUseBLASTSyncTransaction) {
+ return;
+ }
+
+ // Frame callbacks will always occur after submitting draw requests and before
+ // the draw actually occurs. This will ensure that we set the next transaction
+ // for the frame that's about to get drawn and not on a previous frame that.
+ //
+ // This is thread safe since mRtNextFrameReportConsumeWithBlast will only be
+ // modified in onFrameDraw and then again in onFrameComplete. This is to ensure the
+ // next frame completed should be reported with the blast sync transaction.
+ registerRtFrameCallback(createFrameDrawingCallback());
+ mNextDrawUseBLASTSyncTransaction = false;
+ }
+
private void performDraw() {
if (mAttachInfo.mDisplayState == Display.STATE_OFF && !mReportNextDraw) {
return;
@@ -3828,58 +3909,14 @@
mIsDrawing = true;
Trace.traceBegin(Trace.TRACE_TAG_VIEW, "draw");
- boolean usingAsyncReport = false;
- boolean reportNextDraw = mReportNextDraw; // Capture the original value
- if (mAttachInfo.mThreadedRenderer != null && mAttachInfo.mThreadedRenderer.isEnabled()) {
- ArrayList<Runnable> commitCallbacks = mAttachInfo.mTreeObserver
- .captureFrameCommitCallbacks();
- final boolean needFrameCompleteCallback = mNextDrawUseBLASTSyncTransaction ||
- (commitCallbacks != null && commitCallbacks.size() > 0) ||
- mReportNextDraw;
- usingAsyncReport = mReportNextDraw;
- if (needFrameCompleteCallback) {
- final Handler handler = mAttachInfo.mHandler;
- mAttachInfo.mThreadedRenderer.setFrameCompleteCallback((long frameNr) -> {
- finishBLASTSync(!mSendNextFrameToWm);
- handler.postAtFrontOfQueue(() -> {
- if (reportNextDraw) {
- // TODO: Use the frame number
- pendingDrawFinished();
- }
- if (commitCallbacks != null) {
- for (int i = 0; i < commitCallbacks.size(); i++) {
- commitCallbacks.get(i).run();
- }
- }
- });
- });
- }
- }
+ boolean usingAsyncReport = addFrameCompleteCallbackIfNeeded();
+ addFrameCallbackIfNeeded();
try {
- if (mNextDrawUseBLASTSyncTransaction) {
- // Frame callbacks will always occur after submitting draw requests and before
- // the draw actually occurs. This will ensure that we set the next transaction
- // for the frame that's about to get drawn and not on a previous frame that.
- //
- // This is thread safe since mRtNextFrameReportConsumeWithBlast will only be
- // modified in onFrameDraw and then again in onFrameComplete. This is to ensure the
- // next frame completed should be reported with the blast sync transaction.
- registerRtFrameCallback(frame -> {
- mRtNextFrameReportedConsumeWithBlast = true;
- if (mBlastBufferQueue != null) {
- // We don't need to synchronize mRtBLASTSyncTransaction here since it's not
- // being modified and only sent to BlastBufferQueue.
- mBlastBufferQueue.setNextTransaction(mRtBLASTSyncTransaction);
- }
- });
- mNextDrawUseBLASTSyncTransaction = false;
- }
boolean canUseAsync = draw(fullRedrawNeeded);
if (usingAsyncReport && !canUseAsync) {
mAttachInfo.mThreadedRenderer.setFrameCompleteCallback(null);
usingAsyncReport = false;
- finishBLASTSync(true /* apply */);
}
} finally {
mIsDrawing = false;
@@ -7447,7 +7484,7 @@
(int) (mView.getMeasuredHeight() * appScale + 0.5f), viewVisibility,
insetsPending ? WindowManagerGlobal.RELAYOUT_INSETS_PENDING : 0, frameNumber,
mTmpFrames, mPendingMergedConfiguration, mSurfaceControl, mTempInsets,
- mTempControls, mSurfaceSize, mBlastSurfaceControl);
+ mTempControls, mSurfaceSize);
mPendingDisplayCutout.set(mTmpFrames.displayCutout);
mPendingBackDropFrame.set(mTmpFrames.backdropFrame);
if (mSurfaceControl.isValid()) {
@@ -9844,7 +9881,12 @@
mNextDrawUseBLASTSyncTransaction = true;
}
- private void finishBLASTSync(boolean apply) {
+ /**
+ * This should only be called from the render thread.
+ */
+ private void finishBLASTSyncOnRT(boolean apply, Transaction t) {
+ // This is safe to modify on the render thread since the only other place it's modified
+ // is on the UI thread when the render thread is paused.
mSendNextFrameToWm = false;
if (mRtNextFrameReportedConsumeWithBlast) {
mRtNextFrameReportedConsumeWithBlast = false;
@@ -9855,7 +9897,7 @@
if (apply) {
mRtBLASTSyncTransaction.apply();
} else {
- mSurfaceChangedTransaction.merge(mRtBLASTSyncTransaction);
+ t.merge(mRtBLASTSyncTransaction);
}
}
}
@@ -9868,17 +9910,6 @@
return mRtBLASTSyncTransaction;
}
- /**
- * @hide
- */
- public SurfaceControl getRenderSurfaceControl() {
- if (useBLAST()) {
- return mBlastSurfaceControl;
- } else {
- return mSurfaceControl;
- }
- }
-
@Override
public void onDescendantUnbufferedRequested() {
mUnbufferedInputSource = mView.mUnbufferedInputSource;
@@ -9895,4 +9926,8 @@
boolean useBLAST() {
return mUseBLASTAdapter && !mForceDisableBLAST;
}
+
+ int getSurfaceSequenceId() {
+ return mSurfaceSequenceId;
+ }
}
diff --git a/core/java/android/view/WindowlessWindowManager.java b/core/java/android/view/WindowlessWindowManager.java
index dbd8184..0c221ed 100644
--- a/core/java/android/view/WindowlessWindowManager.java
+++ b/core/java/android/view/WindowlessWindowManager.java
@@ -227,8 +227,7 @@
int requestedWidth, int requestedHeight, int viewFlags, int flags, long frameNumber,
ClientWindowFrames outFrames, MergedConfiguration mergedConfiguration,
SurfaceControl outSurfaceControl, InsetsState outInsetsState,
- InsetsSourceControl[] outActiveControls, Point outSurfaceSize,
- SurfaceControl outBLASTSurfaceControl) {
+ InsetsSourceControl[] outActiveControls, Point outSurfaceSize) {
final State state;
synchronized (this) {
state = mStateForWindow.get(window.asBinder());
diff --git a/core/java/android/view/accessibility/AccessibilityEvent.java b/core/java/android/view/accessibility/AccessibilityEvent.java
index d80d230..f6d6fde 100644
--- a/core/java/android/view/accessibility/AccessibilityEvent.java
+++ b/core/java/android/view/accessibility/AccessibilityEvent.java
@@ -199,7 +199,7 @@
* <b>Window state changed</b> - represents the event of a change to a section of
* the user interface that is visually distinct. Should be sent from either the
* root view of a window or from a view that is marked as a pane
- * {@link android.view.View#setAccessibilityPaneTitle(CharSequence)}. Not that changes
+ * {@link android.view.View#setAccessibilityPaneTitle(CharSequence)}. Note that changes
* to true windows are represented by {@link #TYPE_WINDOWS_CHANGED}.</br>
* <em>Type:</em> {@link #TYPE_WINDOW_STATE_CHANGED}</br>
* <em>Properties:</em></br>
diff --git a/core/java/android/window/ITaskOrganizerController.aidl b/core/java/android/window/ITaskOrganizerController.aidl
index 12b16ff..3a84c1f 100644
--- a/core/java/android/window/ITaskOrganizerController.aidl
+++ b/core/java/android/window/ITaskOrganizerController.aidl
@@ -17,7 +17,9 @@
package android.window;
import android.app.ActivityManager;
+import android.content.pm.ParceledListSlice;
import android.window.ITaskOrganizer;
+import android.window.TaskAppearedInfo;
import android.window.WindowContainerToken;
import android.window.WindowContainerTransaction;
@@ -26,8 +28,11 @@
/**
* Register a TaskOrganizer to manage all the tasks with supported windowing modes.
+ *
+ * @return a list of the tasks that should be managed by the organizer, not including tasks
+ * created via {@link #createRootTask}.
*/
- void registerTaskOrganizer(ITaskOrganizer organizer);
+ ParceledListSlice<TaskAppearedInfo> registerTaskOrganizer(ITaskOrganizer organizer);
/**
* Unregisters a previously registered task organizer.
diff --git a/core/java/android/window/TaskAppearedInfo.aidl b/core/java/android/window/TaskAppearedInfo.aidl
new file mode 100644
index 0000000..13eba25f
--- /dev/null
+++ b/core/java/android/window/TaskAppearedInfo.aidl
@@ -0,0 +1,24 @@
+/*
+ * 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.
+ */
+
+package android.window;
+
+/**
+ * Data object for the task info provided when a task is presented to an organizer.
+ * @hide
+ */
+parcelable TaskAppearedInfo;
+
diff --git a/core/java/android/window/TaskAppearedInfo.java b/core/java/android/window/TaskAppearedInfo.java
new file mode 100644
index 0000000..2ff331e
--- /dev/null
+++ b/core/java/android/window/TaskAppearedInfo.java
@@ -0,0 +1,86 @@
+/*
+ * 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.
+ */
+
+package android.window;
+
+import android.annotation.NonNull;
+import android.annotation.TestApi;
+import android.app.ActivityManager.RunningTaskInfo;
+import android.os.Parcel;
+import android.os.Parcelable;
+import android.view.SurfaceControl;
+
+/**
+ * Data object for the task info provided when a task is presented to an organizer.
+ * @hide
+ */
+@TestApi
+public final class TaskAppearedInfo implements Parcelable {
+
+ @NonNull
+ private final RunningTaskInfo mTaskInfo;
+
+ @NonNull
+ private final SurfaceControl mLeash;
+
+ @NonNull
+ public static final Creator<TaskAppearedInfo> CREATOR = new Creator<TaskAppearedInfo>() {
+ @Override
+ public TaskAppearedInfo createFromParcel(Parcel source) {
+ final RunningTaskInfo taskInfo = source.readTypedObject(RunningTaskInfo.CREATOR);
+ final SurfaceControl leash = source.readTypedObject(SurfaceControl.CREATOR);
+ return new TaskAppearedInfo(taskInfo, leash);
+ }
+
+ @Override
+ public TaskAppearedInfo[] newArray(int size) {
+ return new TaskAppearedInfo[size];
+ }
+
+ };
+
+ public TaskAppearedInfo(@NonNull RunningTaskInfo taskInfo, @NonNull SurfaceControl leash) {
+ mTaskInfo = taskInfo;
+ mLeash = leash;
+ }
+
+ @Override
+ public void writeToParcel(@NonNull Parcel dest, int flags) {
+ dest.writeTypedObject(mTaskInfo, flags);
+ dest.writeTypedObject(mLeash, flags);
+ }
+
+ @Override
+ public int describeContents() {
+ return 0;
+ }
+
+ /**
+ * @return the task info.
+ */
+ @NonNull
+ public RunningTaskInfo getTaskInfo() {
+ return mTaskInfo;
+ }
+
+ /**
+ * @return the leash for the task.
+ */
+ @NonNull
+ public SurfaceControl getLeash() {
+ return mLeash;
+ }
+}
diff --git a/core/java/android/window/TaskOrganizer.java b/core/java/android/window/TaskOrganizer.java
index a7cb642..909bb47 100644
--- a/core/java/android/window/TaskOrganizer.java
+++ b/core/java/android/window/TaskOrganizer.java
@@ -17,6 +17,7 @@
package android.window;
import android.annotation.BinderThread;
+import android.annotation.CallSuper;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.annotation.RequiresPermission;
@@ -51,11 +52,16 @@
/**
* Register a TaskOrganizer to manage tasks as they enter a supported windowing mode.
+ *
+ * @return a list of the tasks that should be managed by the organizer, not including tasks
+ * created via {@link #createRootTask}.
*/
@RequiresPermission(android.Manifest.permission.MANAGE_ACTIVITY_STACKS)
- public final void registerOrganizer() {
+ @CallSuper
+ @NonNull
+ public List<TaskAppearedInfo> registerOrganizer() {
try {
- mTaskOrganizerController.registerTaskOrganizer(mInterface);
+ return mTaskOrganizerController.registerTaskOrganizer(mInterface).getList();
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
@@ -63,7 +69,8 @@
/** Unregisters a previously registered task organizer. */
@RequiresPermission(android.Manifest.permission.MANAGE_ACTIVITY_STACKS)
- public final void unregisterOrganizer() {
+ @CallSuper
+ public void unregisterOrganizer() {
try {
mTaskOrganizerController.unregisterTaskOrganizer(mInterface);
} catch (RemoteException e) {
diff --git a/core/java/com/android/internal/accessibility/AccessibilityShortcutController.java b/core/java/com/android/internal/accessibility/AccessibilityShortcutController.java
index 491ddba..2b4e09d 100644
--- a/core/java/com/android/internal/accessibility/AccessibilityShortcutController.java
+++ b/core/java/com/android/internal/accessibility/AccessibilityShortcutController.java
@@ -80,6 +80,8 @@
"com.android.server.accessibility.MagnificationController";
public static final ComponentName MAGNIFICATION_COMPONENT_NAME =
new ComponentName("com.android.server.accessibility", "Magnification");
+ public static final ComponentName REDUCE_BRIGHT_COLORS_COMPONENT_NAME =
+ new ComponentName("com.android.server.accessibility", "ReduceBrightColors");
private static final AudioAttributes VIBRATION_ATTRIBUTES = new AudioAttributes.Builder()
.setContentType(AudioAttributes.CONTENT_TYPE_SONIFICATION)
@@ -126,6 +128,11 @@
Settings.Secure.ACCESSIBILITY_DISPLAY_DALTONIZER_ENABLED,
"1" /* Value to enable */, "0" /* Value to disable */,
R.string.color_correction_feature_name));
+ featuresMap.put(REDUCE_BRIGHT_COLORS_COMPONENT_NAME,
+ new ToggleableFrameworkFeatureInfo(
+ Settings.Secure.REDUCE_BRIGHT_COLORS_ACTIVATED,
+ "1" /* Value to enable */, "0" /* Value to disable */,
+ R.string.reduce_bright_colors_feature_name));
sFrameworkShortcutFeaturesMap = Collections.unmodifiableMap(featuresMap);
}
return sFrameworkShortcutFeaturesMap;
diff --git a/core/java/com/android/internal/accessibility/dialog/AccessibilityTargetHelper.java b/core/java/com/android/internal/accessibility/dialog/AccessibilityTargetHelper.java
index a7c5f6d..9d06bb9 100644
--- a/core/java/com/android/internal/accessibility/dialog/AccessibilityTargetHelper.java
+++ b/core/java/com/android/internal/accessibility/dialog/AccessibilityTargetHelper.java
@@ -21,6 +21,7 @@
import static com.android.internal.accessibility.AccessibilityShortcutController.COLOR_INVERSION_COMPONENT_NAME;
import static com.android.internal.accessibility.AccessibilityShortcutController.DALTONIZER_COMPONENT_NAME;
import static com.android.internal.accessibility.AccessibilityShortcutController.MAGNIFICATION_CONTROLLER_NAME;
+import static com.android.internal.accessibility.AccessibilityShortcutController.REDUCE_BRIGHT_COLORS_COMPONENT_NAME;
import static com.android.internal.accessibility.util.AccessibilityUtils.getAccessibilityServiceFragmentType;
import static com.android.internal.accessibility.util.ShortcutUtils.isShortcutContained;
@@ -112,7 +113,7 @@
@ShortcutType int shortcutType) {
final List<AccessibilityTarget> targets = new ArrayList<>();
targets.addAll(getAccessibilityFilteredTargets(context, shortcutType));
- targets.addAll(getWhiteListingFeatureTargets(context, shortcutType));
+ targets.addAll(getAllowListingFeatureTargets(context, shortcutType));
return targets;
}
@@ -196,12 +197,12 @@
return targets;
}
- private static List<AccessibilityTarget> getWhiteListingFeatureTargets(Context context,
+ private static List<AccessibilityTarget> getAllowListingFeatureTargets(Context context,
@ShortcutType int shortcutType) {
final List<AccessibilityTarget> targets = new ArrayList<>();
- final InvisibleToggleWhiteListingFeatureTarget magnification =
- new InvisibleToggleWhiteListingFeatureTarget(context,
+ final InvisibleToggleAllowListingFeatureTarget magnification =
+ new InvisibleToggleAllowListingFeatureTarget(context,
shortcutType,
isShortcutContained(context, shortcutType, MAGNIFICATION_CONTROLLER_NAME),
MAGNIFICATION_CONTROLLER_NAME,
@@ -209,8 +210,8 @@
context.getDrawable(R.drawable.ic_accessibility_magnification),
Settings.Secure.ACCESSIBILITY_DISPLAY_MAGNIFICATION_NAVBAR_ENABLED);
- final ToggleWhiteListingFeatureTarget daltonizer =
- new ToggleWhiteListingFeatureTarget(context,
+ final ToggleAllowListingFeatureTarget daltonizer =
+ new ToggleAllowListingFeatureTarget(context,
shortcutType,
isShortcutContained(context, shortcutType,
DALTONIZER_COMPONENT_NAME.flattenToString()),
@@ -219,8 +220,8 @@
context.getDrawable(R.drawable.ic_accessibility_color_correction),
Settings.Secure.ACCESSIBILITY_DISPLAY_DALTONIZER_ENABLED);
- final ToggleWhiteListingFeatureTarget colorInversion =
- new ToggleWhiteListingFeatureTarget(context,
+ final ToggleAllowListingFeatureTarget colorInversion =
+ new ToggleAllowListingFeatureTarget(context,
shortcutType,
isShortcutContained(context, shortcutType,
COLOR_INVERSION_COMPONENT_NAME.flattenToString()),
@@ -229,9 +230,21 @@
context.getDrawable(R.drawable.ic_accessibility_color_inversion),
Settings.Secure.ACCESSIBILITY_DISPLAY_INVERSION_ENABLED);
+ // TODO: Update with shortcut icon
+ final ToggleAllowListingFeatureTarget reduceBrightColors =
+ new ToggleAllowListingFeatureTarget(context,
+ shortcutType,
+ isShortcutContained(context, shortcutType,
+ REDUCE_BRIGHT_COLORS_COMPONENT_NAME.flattenToString()),
+ REDUCE_BRIGHT_COLORS_COMPONENT_NAME.flattenToString(),
+ context.getString(R.string.reduce_bright_colors_feature_name),
+ null,
+ Settings.Secure.REDUCE_BRIGHT_COLORS_ACTIVATED);
+
targets.add(magnification);
targets.add(daltonizer);
targets.add(colorInversion);
+ targets.add(reduceBrightColors);
return targets;
}
diff --git a/core/java/com/android/internal/accessibility/dialog/InvisibleToggleWhiteListingFeatureTarget.java b/core/java/com/android/internal/accessibility/dialog/InvisibleToggleAllowListingFeatureTarget.java
similarity index 91%
rename from core/java/com/android/internal/accessibility/dialog/InvisibleToggleWhiteListingFeatureTarget.java
rename to core/java/com/android/internal/accessibility/dialog/InvisibleToggleAllowListingFeatureTarget.java
index acd101b..e78036d 100644
--- a/core/java/com/android/internal/accessibility/dialog/InvisibleToggleWhiteListingFeatureTarget.java
+++ b/core/java/com/android/internal/accessibility/dialog/InvisibleToggleAllowListingFeatureTarget.java
@@ -26,9 +26,9 @@
* Extension for {@link AccessibilityTarget} with {@link AccessibilityFragmentType#INVISIBLE_TOGGLE}
* type.
*/
-class InvisibleToggleWhiteListingFeatureTarget extends AccessibilityTarget {
+class InvisibleToggleAllowListingFeatureTarget extends AccessibilityTarget {
- InvisibleToggleWhiteListingFeatureTarget(Context context, @ShortcutType int shortcutType,
+ InvisibleToggleAllowListingFeatureTarget(Context context, @ShortcutType int shortcutType,
boolean isShortcutSwitched, String id, CharSequence label, Drawable icon, String key) {
super(context, shortcutType, AccessibilityFragmentType.INVISIBLE_TOGGLE,
isShortcutSwitched, id, label, icon, key);
diff --git a/core/java/com/android/internal/accessibility/dialog/ToggleWhiteListingFeatureTarget.java b/core/java/com/android/internal/accessibility/dialog/ToggleAllowListingFeatureTarget.java
similarity index 94%
rename from core/java/com/android/internal/accessibility/dialog/ToggleWhiteListingFeatureTarget.java
rename to core/java/com/android/internal/accessibility/dialog/ToggleAllowListingFeatureTarget.java
index 5ab9eb8..38aac70 100644
--- a/core/java/com/android/internal/accessibility/dialog/ToggleWhiteListingFeatureTarget.java
+++ b/core/java/com/android/internal/accessibility/dialog/ToggleAllowListingFeatureTarget.java
@@ -32,9 +32,9 @@
* Extension for {@link AccessibilityTarget} with {@link AccessibilityFragmentType#TOGGLE}
* type.
*/
-class ToggleWhiteListingFeatureTarget extends AccessibilityTarget {
+class ToggleAllowListingFeatureTarget extends AccessibilityTarget {
- ToggleWhiteListingFeatureTarget(Context context, @ShortcutType int shortcutType,
+ ToggleAllowListingFeatureTarget(Context context, @ShortcutType int shortcutType,
boolean isShortcutSwitched, String id, CharSequence label, Drawable icon, String key) {
super(context, shortcutType, AccessibilityFragmentType.TOGGLE,
isShortcutSwitched, id, label, icon, key);
diff --git a/core/java/com/android/internal/os/BatteryStatsImpl.java b/core/java/com/android/internal/os/BatteryStatsImpl.java
index 17323ba..4c5f988 100644
--- a/core/java/com/android/internal/os/BatteryStatsImpl.java
+++ b/core/java/com/android/internal/os/BatteryStatsImpl.java
@@ -65,7 +65,6 @@
import android.telephony.CellSignalStrength;
import android.telephony.DataConnectionRealTimeInfo;
import android.telephony.ModemActivityInfo;
-import android.telephony.ModemActivityInfo.TransmitPower;
import android.telephony.ServiceState;
import android.telephony.SignalStrength;
import android.telephony.TelephonyManager;
@@ -7791,7 +7790,7 @@
public ControllerActivityCounterImpl getOrCreateModemControllerActivityLocked() {
if (mModemControllerActivity == null) {
mModemControllerActivity = new ControllerActivityCounterImpl(mBsi.mOnBatteryTimeBase,
- ModemActivityInfo.TX_POWER_LEVELS);
+ ModemActivityInfo.getNumTxPowerLevels());
}
return mModemControllerActivity;
}
@@ -9257,7 +9256,7 @@
if (in.readInt() != 0) {
mModemControllerActivity = new ControllerActivityCounterImpl(mBsi.mOnBatteryTimeBase,
- ModemActivityInfo.TX_POWER_LEVELS, in);
+ ModemActivityInfo.getNumTxPowerLevels(), in);
} else {
mModemControllerActivity = null;
}
@@ -10520,7 +10519,7 @@
mBluetoothActivity = new ControllerActivityCounterImpl(mOnBatteryTimeBase,
NUM_BT_TX_LEVELS);
mModemActivity = new ControllerActivityCounterImpl(mOnBatteryTimeBase,
- ModemActivityInfo.TX_POWER_LEVELS);
+ ModemActivityInfo.getNumTxPowerLevels());
mMobileRadioActiveTimer = new StopwatchTimer(mClocks, null, -400, null, mOnBatteryTimeBase);
mMobileRadioActivePerAppTimer = new StopwatchTimer(mClocks, null, -401, null,
mOnBatteryTimeBase);
@@ -11710,26 +11709,7 @@
}
}
- private ModemActivityInfo mLastModemActivityInfo =
- new ModemActivityInfo(0, 0, 0, new int[0], 0);
-
- private ModemActivityInfo getDeltaModemActivityInfo(ModemActivityInfo activityInfo) {
- if (activityInfo == null) {
- return null;
- }
- int[] txTimeMs = new int[ModemActivityInfo.TX_POWER_LEVELS];
- for (int i = 0; i < ModemActivityInfo.TX_POWER_LEVELS; i++) {
- txTimeMs[i] = activityInfo.getTransmitPowerInfo().get(i).getTimeInMillis()
- - mLastModemActivityInfo.getTransmitPowerInfo().get(i).getTimeInMillis();
- }
- ModemActivityInfo deltaInfo = new ModemActivityInfo(activityInfo.getTimestamp(),
- activityInfo.getSleepTimeMillis() - mLastModemActivityInfo.getSleepTimeMillis(),
- activityInfo.getIdleTimeMillis() - mLastModemActivityInfo.getIdleTimeMillis(),
- txTimeMs,
- activityInfo.getReceiveTimeMillis() - mLastModemActivityInfo.getReceiveTimeMillis());
- mLastModemActivityInfo = activityInfo;
- return deltaInfo;
- }
+ private ModemActivityInfo mLastModemActivityInfo = null;
/**
* Distribute Cell radio energy info and network traffic to apps.
@@ -11746,7 +11726,9 @@
if (DEBUG_ENERGY) {
Slog.d(TAG, "Updating mobile radio stats with " + activityInfo);
}
- ModemActivityInfo deltaInfo = getDeltaModemActivityInfo(activityInfo);
+ ModemActivityInfo deltaInfo = mLastModemActivityInfo == null ? activityInfo
+ : mLastModemActivityInfo.getDelta(activityInfo);
+ mLastModemActivityInfo = activityInfo;
// Add modem tx power to history.
addModemTxPowerToHistory(deltaInfo, elapsedRealtimeMs, uptimeMs);
@@ -11778,10 +11760,9 @@
mModemActivity.getSleepTimeCounter().addCountLocked(
deltaInfo.getSleepTimeMillis());
mModemActivity.getRxTimeCounter().addCountLocked(deltaInfo.getReceiveTimeMillis());
- for (int lvl = 0; lvl < ModemActivityInfo.TX_POWER_LEVELS; lvl++) {
+ for (int lvl = 0; lvl < ModemActivityInfo.getNumTxPowerLevels(); lvl++) {
mModemActivity.getTxTimeCounters()[lvl]
- .addCountLocked(deltaInfo.getTransmitPowerInfo()
- .get(lvl).getTimeInMillis());
+ .addCountLocked(deltaInfo.getTransmitDurationMillisAtPowerLevel(lvl));
}
// POWER_MODEM_CONTROLLER_OPERATING_VOLTAGE is measured in mV, so convert to V.
@@ -11795,11 +11776,11 @@
mPowerProfile.getAveragePower(PowerProfile.POWER_MODEM_CONTROLLER_IDLE)
+ deltaInfo.getReceiveTimeMillis() *
mPowerProfile.getAveragePower(PowerProfile.POWER_MODEM_CONTROLLER_RX);
- List<TransmitPower> txPowerInfo = deltaInfo.getTransmitPowerInfo();
- for (int i = 0; i < Math.min(txPowerInfo.size(),
+ for (int i = 0; i < Math.min(ModemActivityInfo.getNumTxPowerLevels(),
CellSignalStrength.getNumSignalStrengthLevels()); i++) {
- energyUsed += txPowerInfo.get(i).getTimeInMillis() * mPowerProfile
- .getAveragePower(PowerProfile.POWER_MODEM_CONTROLLER_TX, i);
+ energyUsed += deltaInfo.getTransmitDurationMillisAtPowerLevel(i)
+ * mPowerProfile.getAveragePower(
+ PowerProfile.POWER_MODEM_CONTROLLER_TX, i);
}
// We store the power drain as mAms.
@@ -11894,10 +11875,10 @@
}
if (totalTxPackets > 0 && entry.txPackets > 0) {
- for (int lvl = 0; lvl < ModemActivityInfo.TX_POWER_LEVELS; lvl++) {
- long txMs =
- entry.txPackets * deltaInfo.getTransmitPowerInfo()
- .get(lvl).getTimeInMillis();
+ for (int lvl = 0; lvl < ModemActivityInfo.getNumTxPowerLevels();
+ lvl++) {
+ long txMs = entry.txPackets
+ * deltaInfo.getTransmitDurationMillisAtPowerLevel(lvl);
txMs /= totalTxPackets;
activityCounter.getTxTimeCounters()[lvl].addCountLocked(txMs);
}
@@ -11929,18 +11910,14 @@
if (activityInfo == null) {
return;
}
- List<TransmitPower> txPowerInfo = activityInfo.getTransmitPowerInfo();
- if (txPowerInfo == null || txPowerInfo.size() != ModemActivityInfo.TX_POWER_LEVELS) {
- return;
- }
int levelMaxTimeSpent = 0;
- for (int i = 1; i < txPowerInfo.size(); i++) {
- if (txPowerInfo.get(i).getTimeInMillis() > txPowerInfo.get(levelMaxTimeSpent)
- .getTimeInMillis()) {
+ for (int i = 1; i < ModemActivityInfo.getNumTxPowerLevels(); i++) {
+ if (activityInfo.getTransmitDurationMillisAtPowerLevel(i)
+ > activityInfo.getTransmitDurationMillisAtPowerLevel(levelMaxTimeSpent)) {
levelMaxTimeSpent = i;
}
}
- if (levelMaxTimeSpent == ModemActivityInfo.TX_POWER_LEVELS - 1) {
+ if (levelMaxTimeSpent == ModemActivityInfo.getNumTxPowerLevels() - 1) {
mHistoryCur.states2 |= HistoryItem.STATE2_CELLULAR_HIGH_TX_POWER_FLAG;
addHistoryRecordLocked(elapsedRealtimeMs, uptimeMs);
}
@@ -13462,7 +13439,7 @@
timeInRxSignalStrengthLevelMs[i] =
getPhoneSignalStrengthTime(i, rawRealTimeUs, which) / 1000;
}
- long[] txTimeMs = new long[Math.min(ModemActivityInfo.TX_POWER_LEVELS,
+ long[] txTimeMs = new long[Math.min(ModemActivityInfo.getNumTxPowerLevels(),
counter.getTxTimeCounters().length)];
long totalTxTimeMs = 0;
for (int i = 0; i < txTimeMs.length; i++) {
@@ -15601,7 +15578,7 @@
mBluetoothActivity = new ControllerActivityCounterImpl(mOnBatteryTimeBase,
NUM_BT_TX_LEVELS, in);
mModemActivity = new ControllerActivityCounterImpl(mOnBatteryTimeBase,
- ModemActivityInfo.TX_POWER_LEVELS, in);
+ ModemActivityInfo.getNumTxPowerLevels(), in);
mHasWifiReporting = in.readInt() != 0;
mHasBluetoothReporting = in.readInt() != 0;
mHasModemReporting = in.readInt() != 0;
diff --git a/core/java/com/android/internal/statusbar/IStatusBar.aidl b/core/java/com/android/internal/statusbar/IStatusBar.aidl
index caae518..77c7ce8 100644
--- a/core/java/com/android/internal/statusbar/IStatusBar.aidl
+++ b/core/java/com/android/internal/statusbar/IStatusBar.aidl
@@ -102,6 +102,13 @@
void onCameraLaunchGestureDetected(int source);
/**
+ * Notifies the status bar that the Emergency Action launch gesture has been detected.
+ *
+ * TODO(b/169175022) Update method name and docs when feature name is locked.
+ */
+ void onEmergencyActionLaunchGestureDetected();
+
+ /**
* Shows the picture-in-picture menu if an activity is in picture-in-picture mode.
*/
void showPictureInPictureMenu();
diff --git a/core/jni/android_view_InputEventReceiver.cpp b/core/jni/android_view_InputEventReceiver.cpp
index 9ed71ac0..1ea918a 100644
--- a/core/jni/android_view_InputEventReceiver.cpp
+++ b/core/jni/android_view_InputEventReceiver.cpp
@@ -343,7 +343,7 @@
jboolean(focusEvent->getHasFocus()),
jboolean(focusEvent->getInTouchMode()));
finishInputEvent(seq, true /* handled */);
- return OK;
+ continue;
}
default:
diff --git a/core/proto/android/app/settings_enums.proto b/core/proto/android/app/settings_enums.proto
index 32ce5e2..99fe1af 100644
--- a/core/proto/android/app/settings_enums.proto
+++ b/core/proto/android/app/settings_enums.proto
@@ -2756,4 +2756,9 @@
// CATEGORY: SETTINGS
// OS: S
SCREEN_TIMEOUT = 1852;
+
+ // OPEN: Settings > Accessibility > Reduce Bright Colors
+ // CATEGORY: SETTINGS
+ // OS: S
+ REDUCE_BRIGHT_COLORS_SETTINGS = 1853;
}
diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml
index e2f4f2f..f2af514 100644
--- a/core/res/AndroidManifest.xml
+++ b/core/res/AndroidManifest.xml
@@ -4518,6 +4518,12 @@
<permission android:name="android.permission.MANAGE_NOTIFICATIONS"
android:protectionLevel="signature" />
+ <!-- @SystemApi @TestApi Allows adding/removing enabled notification listener components.
+ @hide -->
+ <permission android:name="android.permission.MANAGE_NOTIFICATION_LISTENERS"
+ android:protectionLevel="signature" />
+ <uses-permission android:name="android.permission.MANAGE_NOTIFICATION_LISTENERS" />
+
<!-- Allows notifications to be colorized
<p>Not for use by third-party applications. @hide -->
<permission android:name="android.permission.USE_COLORIZED_NOTIFICATIONS"
diff --git a/core/res/res/values/strings.xml b/core/res/res/values/strings.xml
index fc489b1..645bae7 100644
--- a/core/res/res/values/strings.xml
+++ b/core/res/res/values/strings.xml
@@ -4494,6 +4494,9 @@
shown in the warning dialog about the accessibility shortcut. -->
<string name="color_correction_feature_name">Color Correction</string>
+ <!-- Title of Reduce Bright Colors feature, shown in the warning dialog about the accessibility shortcut. [CHAR LIMIT=none] -->
+ <string name="reduce_bright_colors_feature_name">Reduce Bright Colors</string>
+
<!-- Text in toast to alert the user that the accessibility shortcut turned on an accessibility service. [CHAR LIMIT=none] -->
<string name="accessibility_shortcut_enabling_service">Held volume keys. <xliff:g id="service_name" example="TalkBack">%1$s</xliff:g> turned on.</string>
diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml
index 1249b17..9b52f54 100644
--- a/core/res/res/values/symbols.xml
+++ b/core/res/res/values/symbols.xml
@@ -3249,6 +3249,7 @@
<java-symbol type="string" name="accessibility_shortcut_disabling_service" />
<java-symbol type="string" name="color_inversion_feature_name" />
<java-symbol type="string" name="color_correction_feature_name" />
+ <java-symbol type="string" name="reduce_bright_colors_feature_name" />
<java-symbol type="string" name="config_defaultAccessibilityService" />
<java-symbol type="string" name="accessibility_shortcut_spoken_feedback" />
diff --git a/data/etc/car/Android.bp b/data/etc/car/Android.bp
index e122e00..745de84 100644
--- a/data/etc/car/Android.bp
+++ b/data/etc/car/Android.bp
@@ -149,3 +149,11 @@
src: "com.android.car.ui.paintbooth.xml",
filename_from_src: true,
}
+
+prebuilt_etc {
+ name: "allowed_privapp_com.android.car.provision",
+ system_ext_specific: true,
+ sub_dir: "permissions",
+ src: "com.android.car.provision.xml",
+ filename_from_src: true,
+}
\ No newline at end of file
diff --git a/data/etc/car/com.android.car.provision.xml b/data/etc/car/com.android.car.provision.xml
new file mode 100644
index 0000000..fa51d55e
--- /dev/null
+++ b/data/etc/car/com.android.car.provision.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ ~ 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
+ -->
+<permissions>
+ <privapp-permissions package="com.android.car.provision">
+ <permission name="android.permission.WRITE_SECURE_SETTINGS"/>
+ <permission name="android.permission.WRITE_SETTINGS"/>
+ </privapp-permissions>
+</permissions>
diff --git a/graphics/java/android/graphics/Paint.java b/graphics/java/android/graphics/Paint.java
index 28d7911..a191fe5 100644
--- a/graphics/java/android/graphics/Paint.java
+++ b/graphics/java/android/graphics/Paint.java
@@ -115,6 +115,21 @@
Align.LEFT, Align.CENTER, Align.RIGHT
};
+ /** @hide */
+ @Retention(RetentionPolicy.SOURCE)
+ @IntDef(flag = true, value = {
+ ANTI_ALIAS_FLAG,
+ FILTER_BITMAP_FLAG,
+ DITHER_FLAG,
+ UNDERLINE_TEXT_FLAG,
+ STRIKE_THRU_TEXT_FLAG,
+ FAKE_BOLD_TEXT_FLAG,
+ LINEAR_TEXT_FLAG,
+ SUBPIXEL_TEXT_FLAG,
+ EMBEDDED_BITMAP_TEXT_FLAG
+ })
+ public @interface PaintFlag{}
+
/**
* Paint flag that enables antialiasing when drawing.
*
@@ -724,7 +739,7 @@
*
* @return the paint's flags (see enums ending in _Flag for bit masks)
*/
- public int getFlags() {
+ public @PaintFlag int getFlags() {
return nGetFlags(mNativePaint);
}
@@ -733,7 +748,7 @@
*
* @param flags The new flag bits for the paint
*/
- public void setFlags(int flags) {
+ public void setFlags(@PaintFlag int flags) {
nSetFlags(mNativePaint, flags);
}
diff --git a/libs/WindowManager/Shell/res/raw/wm_shell_protolog.json b/libs/WindowManager/Shell/res/raw/wm_shell_protolog.json
index bcef154..44744bc 100644
--- a/libs/WindowManager/Shell/res/raw/wm_shell_protolog.json
+++ b/libs/WindowManager/Shell/res/raw/wm_shell_protolog.json
@@ -7,6 +7,12 @@
"group": "WM_SHELL_TASK_ORG",
"at": "com\/android\/wm\/shell\/ShellTaskOrganizer.java"
},
+ "-1683614271": {
+ "message": "Existing task: id=%d component=%s",
+ "level": "VERBOSE",
+ "group": "WM_SHELL_TASK_ORG",
+ "at": "com\/android\/wm\/shell\/ShellTaskOrganizer.java"
+ },
"-1534364071": {
"message": "onTransitionReady %s: %s",
"level": "VERBOSE",
@@ -61,6 +67,12 @@
"group": "WM_SHELL_TASK_ORG",
"at": "com\/android\/wm\/shell\/FullscreenTaskListener.java"
},
+ "580605218": {
+ "message": "Registering organizer",
+ "level": "VERBOSE",
+ "group": "WM_SHELL_TASK_ORG",
+ "at": "com\/android\/wm\/shell\/ShellTaskOrganizer.java"
+ },
"980952660": {
"message": "Task root back pressed taskId=%d",
"level": "VERBOSE",
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/ShellTaskOrganizer.java b/libs/WindowManager/Shell/src/com/android/wm/shell/ShellTaskOrganizer.java
index 7ce65fd..d87de5a 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/ShellTaskOrganizer.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/ShellTaskOrganizer.java
@@ -28,12 +28,14 @@
import android.app.ActivityManager.RunningTaskInfo;
import android.app.WindowConfiguration.WindowingMode;
import android.util.Log;
-import android.util.Pair;
import android.util.SparseArray;
import android.view.SurfaceControl;
import android.window.ITaskOrganizerController;
+import android.window.TaskAppearedInfo;
import android.window.TaskOrganizer;
+import androidx.annotation.NonNull;
+
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.protolog.common.ProtoLog;
import com.android.wm.shell.common.ShellExecutor;
@@ -42,6 +44,7 @@
import com.android.wm.shell.protolog.ShellProtoLogGroup;
import java.util.Arrays;
+import java.util.List;
/**
* Unified task organizer for all components in the shell.
@@ -82,7 +85,7 @@
// Keeps track of all the tasks reported to this organizer (changes in windowing mode will
// require us to report to both old and new listeners)
- private final SparseArray<Pair<RunningTaskInfo, SurfaceControl>> mTasks = new SparseArray<>();
+ private final SparseArray<TaskAppearedInfo> mTasks = new SparseArray<>();
// TODO(shell-transitions): move to a more "global" Shell location as this isn't only for Tasks
private final Transitions mTransitions;
@@ -102,6 +105,19 @@
if (Transitions.ENABLE_SHELL_TRANSITIONS) registerTransitionPlayer(mTransitions);
}
+ @Override
+ public List<TaskAppearedInfo> registerOrganizer() {
+ ProtoLog.v(ShellProtoLogGroup.WM_SHELL_TASK_ORG, "Registering organizer");
+ final List<TaskAppearedInfo> taskInfos = super.registerOrganizer();
+ for (int i = 0; i < taskInfos.size(); i++) {
+ final TaskAppearedInfo info = taskInfos.get(i);
+ ProtoLog.v(ShellProtoLogGroup.WM_SHELL_TASK_ORG, "Existing task: id=%d component=%s",
+ info.getTaskInfo().taskId, info.getTaskInfo().baseIntent);
+ onTaskAppeared(info.getTaskInfo(), info.getLeash());
+ }
+ return taskInfos;
+ }
+
/**
* Adds a listener for tasks with given types.
*/
@@ -117,10 +133,11 @@
// Notify the listener of all existing tasks with the given type.
for (int i = mTasks.size() - 1; i >= 0; i--) {
- Pair<RunningTaskInfo, SurfaceControl> data = mTasks.valueAt(i);
- final @TaskListenerType int taskListenerType = getTaskListenerType(data.first);
+ TaskAppearedInfo data = mTasks.valueAt(i);
+ final @TaskListenerType int taskListenerType = getTaskListenerType(
+ data.getTaskInfo());
if (taskListenerType == listenerType) {
- listener.onTaskAppeared(data.first, data.second);
+ listener.onTaskAppeared(data.getTaskInfo(), data.getLeash());
}
}
}
@@ -143,7 +160,7 @@
public void onTaskAppeared(RunningTaskInfo taskInfo, SurfaceControl leash) {
ProtoLog.v(ShellProtoLogGroup.WM_SHELL_TASK_ORG, "Task appeared taskId=%d",
taskInfo.taskId);
- mTasks.put(taskInfo.taskId, new Pair<>(taskInfo, leash));
+ mTasks.put(taskInfo.taskId, new TaskAppearedInfo(taskInfo, leash));
final TaskListener listener = mTaskListenersByType.get(getTaskListenerType(taskInfo));
if (listener != null) {
listener.onTaskAppeared(taskInfo, leash);
@@ -154,10 +171,10 @@
public void onTaskInfoChanged(RunningTaskInfo taskInfo) {
ProtoLog.v(ShellProtoLogGroup.WM_SHELL_TASK_ORG, "Task info changed taskId=%d",
taskInfo.taskId);
- final Pair<RunningTaskInfo, SurfaceControl> data = mTasks.get(taskInfo.taskId);
+ final TaskAppearedInfo data = mTasks.get(taskInfo.taskId);
final @TaskListenerType int listenerType = getTaskListenerType(taskInfo);
- final @TaskListenerType int prevListenerType = getTaskListenerType(data.first);
- mTasks.put(taskInfo.taskId, new Pair<>(taskInfo, data.second));
+ final @TaskListenerType int prevListenerType = getTaskListenerType(data.getTaskInfo());
+ mTasks.put(taskInfo.taskId, new TaskAppearedInfo(taskInfo, data.getLeash()));
if (prevListenerType != listenerType) {
// TODO: We currently send vanished/appeared as the task moves between types, but
// we should consider adding a different mode-changed callback
@@ -167,7 +184,7 @@
}
listener = mTaskListenersByType.get(listenerType);
if (listener != null) {
- SurfaceControl leash = data.second;
+ SurfaceControl leash = data.getLeash();
listener.onTaskAppeared(taskInfo, leash);
}
} else {
@@ -193,7 +210,7 @@
ProtoLog.v(ShellProtoLogGroup.WM_SHELL_TASK_ORG, "Task vanished taskId=%d",
taskInfo.taskId);
final @TaskListenerType int prevListenerType =
- getTaskListenerType(mTasks.get(taskInfo.taskId).first);
+ getTaskListenerType(mTasks.get(taskInfo.taskId).getTaskInfo());
mTasks.remove(taskInfo.taskId);
final TaskListener listener = mTaskListenersByType.get(prevListenerType);
if (listener != null) {
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/common/SystemWindows.java b/libs/WindowManager/Shell/src/com/android/wm/shell/common/SystemWindows.java
index 84b98f9..17fd16b 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/common/SystemWindows.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/common/SystemWindows.java
@@ -276,12 +276,11 @@
long frameNumber, ClientWindowFrames outFrames,
MergedConfiguration mergedConfiguration,
SurfaceControl outSurfaceControl, InsetsState outInsetsState,
- InsetsSourceControl[] outActiveControls, Point outSurfaceSize,
- SurfaceControl outBLASTSurfaceControl) {
+ InsetsSourceControl[] outActiveControls, Point outSurfaceSize) {
int res = super.relayout(window, attrs, requestedWidth, requestedHeight,
viewVisibility, flags, frameNumber, outFrames,
mergedConfiguration, outSurfaceControl, outInsetsState,
- outActiveControls, outSurfaceSize, outBLASTSurfaceControl);
+ outActiveControls, outSurfaceSize);
if (res != 0) {
return res;
}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/protolog/ShellProtoLogGroup.java b/libs/WindowManager/Shell/src/com/android/wm/shell/protolog/ShellProtoLogGroup.java
index a0ce9da..f3dadfc 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/protolog/ShellProtoLogGroup.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/protolog/ShellProtoLogGroup.java
@@ -26,7 +26,7 @@
public enum ShellProtoLogGroup implements IProtoLogGroup {
// NOTE: Since we enable these from the same WM ShellCommand, these names should not conflict
// with those in the framework ProtoLogGroup
- WM_SHELL_TASK_ORG(Consts.ENABLE_DEBUG, Consts.ENABLE_LOG_TO_PROTO_DEBUG, false,
+ WM_SHELL_TASK_ORG(Consts.ENABLE_DEBUG, Consts.ENABLE_LOG_TO_PROTO_DEBUG, true,
Consts.TAG_WM_SHELL),
WM_SHELL_TRANSITIONS(Consts.ENABLE_DEBUG, Consts.ENABLE_LOG_TO_PROTO_DEBUG, true,
Consts.TAG_WM_SHELL),
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/ShellTaskOrganizerTests.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/ShellTaskOrganizerTests.java
index f01fc51..5418a5b 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/ShellTaskOrganizerTests.java
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/ShellTaskOrganizerTests.java
@@ -22,6 +22,10 @@
import static com.android.wm.shell.ShellTaskOrganizer.TASK_LISTENER_TYPE_MULTI_WINDOW;
import static com.android.wm.shell.ShellTaskOrganizer.TASK_LISTENER_TYPE_PIP;
+import static com.android.dx.mockito.inline.extended.ExtendedMockito.doReturn;
+import static com.android.dx.mockito.inline.extended.ExtendedMockito.spy;
+import static com.android.dx.mockito.inline.extended.ExtendedMockito.when;
+
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;
import static org.mockito.ArgumentMatchers.any;
@@ -29,10 +33,12 @@
import static org.mockito.Mockito.verify;
import android.app.ActivityManager.RunningTaskInfo;
+import android.content.pm.ParceledListSlice;
import android.os.RemoteException;
import android.view.SurfaceControl;
import android.window.ITaskOrganizer;
import android.window.ITaskOrganizerController;
+import android.window.TaskAppearedInfo;
import androidx.test.ext.junit.runners.AndroidJUnit4;
import androidx.test.filters.SmallTest;
@@ -93,8 +99,12 @@
@Before
public void setUp() {
MockitoAnnotations.initMocks(this);
- mOrganizer = new ShellTaskOrganizer(mTaskOrganizerController, mSyncTransactionQueue,
- mTransactionPool, mTestExecutor, mTestExecutor);
+ try {
+ doReturn(ParceledListSlice.<TaskAppearedInfo>emptyList())
+ .when(mTaskOrganizerController).registerTaskOrganizer(any());
+ } catch (RemoteException e) {}
+ mOrganizer = spy(new ShellTaskOrganizer(mTaskOrganizerController, mSyncTransactionQueue,
+ mTransactionPool, mTestExecutor, mTestExecutor));
}
@Test
@@ -116,8 +126,29 @@
}
@Test
+ public void testRegisterWithExistingTasks() throws RemoteException {
+ // Setup some tasks
+ RunningTaskInfo task1 = createTaskInfo(1, WINDOWING_MODE_MULTI_WINDOW);
+ RunningTaskInfo task2 = createTaskInfo(2, WINDOWING_MODE_MULTI_WINDOW);
+ ArrayList<TaskAppearedInfo> taskInfos = new ArrayList<>();
+ taskInfos.add(new TaskAppearedInfo(task1, new SurfaceControl()));
+ taskInfos.add(new TaskAppearedInfo(task2, new SurfaceControl()));
+ doReturn(new ParceledListSlice(taskInfos))
+ .when(mTaskOrganizerController).registerTaskOrganizer(any());
+
+ // Register and expect the tasks to be stored
+ mOrganizer.registerOrganizer();
+
+ // Check that the tasks are next reported when the listener is added
+ TrackingTaskListener listener = new TrackingTaskListener();
+ mOrganizer.addListener(listener, TASK_LISTENER_TYPE_MULTI_WINDOW);
+ assertTrue(listener.appeared.contains(task1));
+ assertTrue(listener.appeared.contains(task2));
+ }
+
+ @Test
public void testAppearedVanished() {
- RunningTaskInfo taskInfo = createTaskInfo(WINDOWING_MODE_MULTI_WINDOW);
+ RunningTaskInfo taskInfo = createTaskInfo(1, WINDOWING_MODE_MULTI_WINDOW);
TrackingTaskListener listener = new TrackingTaskListener();
mOrganizer.addListener(listener, TASK_LISTENER_TYPE_MULTI_WINDOW);
mOrganizer.onTaskAppeared(taskInfo, null);
@@ -129,7 +160,7 @@
@Test
public void testAddListenerExistingTasks() {
- RunningTaskInfo taskInfo = createTaskInfo(WINDOWING_MODE_MULTI_WINDOW);
+ RunningTaskInfo taskInfo = createTaskInfo(1, WINDOWING_MODE_MULTI_WINDOW);
mOrganizer.onTaskAppeared(taskInfo, null);
TrackingTaskListener listener = new TrackingTaskListener();
@@ -139,7 +170,7 @@
@Test
public void testWindowingModeChange() {
- RunningTaskInfo taskInfo = createTaskInfo(WINDOWING_MODE_MULTI_WINDOW);
+ RunningTaskInfo taskInfo = createTaskInfo(1, WINDOWING_MODE_MULTI_WINDOW);
TrackingTaskListener mwListener = new TrackingTaskListener();
TrackingTaskListener pipListener = new TrackingTaskListener();
mOrganizer.addListener(mwListener, TASK_LISTENER_TYPE_MULTI_WINDOW);
@@ -148,14 +179,15 @@
assertTrue(mwListener.appeared.contains(taskInfo));
assertTrue(pipListener.appeared.isEmpty());
- taskInfo = createTaskInfo(WINDOWING_MODE_PINNED);
+ taskInfo = createTaskInfo(1, WINDOWING_MODE_PINNED);
mOrganizer.onTaskInfoChanged(taskInfo);
assertTrue(mwListener.vanished.contains(taskInfo));
assertTrue(pipListener.appeared.contains(taskInfo));
}
- private RunningTaskInfo createTaskInfo(int windowingMode) {
+ private RunningTaskInfo createTaskInfo(int taskId, int windowingMode) {
RunningTaskInfo taskInfo = new RunningTaskInfo();
+ taskInfo.taskId = taskId;
taskInfo.configuration.windowConfiguration.setWindowingMode(windowingMode);
return taskInfo;
}
diff --git a/location/java/android/location/LocationRequest.java b/location/java/android/location/LocationRequest.java
index e03643c..4977c21 100644
--- a/location/java/android/location/LocationRequest.java
+++ b/location/java/android/location/LocationRequest.java
@@ -21,6 +21,7 @@
import android.Manifest;
import android.annotation.FloatRange;
+import android.annotation.IntDef;
import android.annotation.IntRange;
import android.annotation.NonNull;
import android.annotation.Nullable;
@@ -38,6 +39,8 @@
import com.android.internal.util.Preconditions;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
import java.util.Objects;
@@ -65,16 +68,41 @@
*/
public static final long PASSIVE_INTERVAL = Long.MAX_VALUE;
+ /** @hide */
+ @Retention(RetentionPolicy.SOURCE)
+ @IntDef({QUALITY_LOW_POWER, QUALITY_BALANCED_POWER_ACCURACY, QUALITY_HIGH_ACCURACY})
+ public @interface Quality {}
+
+ /**
+ * A quality constant indicating a location provider may choose to satisfy this request by
+ * providing very accurate locations at the expense of potentially increased power usage.
+ */
+ public static final int QUALITY_HIGH_ACCURACY = 100;
+
+ /**
+ * A quality constant indicating a location provider may choose to satisfy this request by
+ * equally balancing power and accuracy constraints.
+ */
+ public static final int QUALITY_BALANCED_POWER_ACCURACY = 102;
+
+ /**
+ * A quality constant indicating a location provider may choose to satisfy this request by
+ * providing less accurate locations in order to save power.
+ */
+ public static final int QUALITY_LOW_POWER = 104;
+
/**
* Used with {@link #setQuality} to request the most accurate locations available.
*
* <p>This may be up to 1 meter accuracy, although this is implementation dependent.
*
* @hide
+ * @deprecated Use {@link #QUALITY_HIGH_ACCURACY} instead.
*/
+ @Deprecated
@SystemApi
@TestApi
- public static final int ACCURACY_FINE = 100;
+ public static final int ACCURACY_FINE = QUALITY_HIGH_ACCURACY;
/**
* Used with {@link #setQuality} to request "block" level accuracy.
@@ -84,10 +112,12 @@
* such as this often consumes less power.
*
* @hide
+ * @deprecated Use {@link #QUALITY_BALANCED_POWER_ACCURACY} instead.
*/
+ @Deprecated
@SystemApi
@TestApi
- public static final int ACCURACY_BLOCK = 102;
+ public static final int ACCURACY_BLOCK = QUALITY_BALANCED_POWER_ACCURACY;
/**
* Used with {@link #setQuality} to request "city" level accuracy.
@@ -97,10 +127,12 @@
* such as this often consumes less power.
*
* @hide
+ * @deprecated Use {@link #QUALITY_LOW_POWER} instead.
*/
+ @Deprecated
@SystemApi
@TestApi
- public static final int ACCURACY_CITY = 104;
+ public static final int ACCURACY_CITY = QUALITY_LOW_POWER;
/**
* Used with {@link #setQuality} to require no direct power impact (passive locations).
@@ -123,7 +155,9 @@
* possible.
*
* @hide
+ * @deprecated Use {@link #QUALITY_LOW_POWER} instead.
*/
+ @Deprecated
@SystemApi
@TestApi
public static final int POWER_LOW = 201;
@@ -134,7 +168,9 @@
* <p>This location request will allow high power location work.
*
* @hide
+ * @deprecated Use {@link #QUALITY_HIGH_ACCURACY} instead.
*/
+ @Deprecated
@SystemApi
@TestApi
public static final int POWER_HIGH = 203;
@@ -144,7 +180,7 @@
@UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, publicAlternatives = "Use {@link "
+ "LocationManager} methods to provide the provider explicitly.")
@Nullable private String mProvider;
- private int mQuality;
+ private @Quality int mQuality;
@UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, publicAlternatives = "Use {@link "
+ "LocationRequest} instead.")
private long mInterval;
@@ -168,7 +204,7 @@
public static LocationRequest create() {
// 60 minutes is the default legacy interval
return new LocationRequest.Builder(60 * 60 * 1000)
- .setQuality(POWER_LOW)
+ .setQuality(QUALITY_LOW_POWER)
.build();
}
@@ -241,7 +277,7 @@
private LocationRequest(
@Nullable String provider,
long intervalMillis,
- int quality,
+ @Quality int quality,
long expireAtRealtimeMillis,
long durationMillis,
int maxUpdates,
@@ -251,9 +287,6 @@
boolean locationSettingsIgnored,
boolean lowPower,
WorkSource workSource) {
- Preconditions.checkArgument(intervalMillis != PASSIVE_INTERVAL || quality == POWER_NONE);
- Preconditions.checkArgument(minUpdateIntervalMillis <= intervalMillis);
-
mProvider = provider;
mInterval = intervalMillis;
mQuality = quality;
@@ -297,24 +330,39 @@
@SystemApi
@Deprecated
public @NonNull LocationRequest setQuality(int quality) {
- mQuality = Builder.checkQuality(quality, true);
+ switch (quality) {
+ case POWER_HIGH:
+ // fall through
+ case ACCURACY_FINE:
+ mQuality = QUALITY_HIGH_ACCURACY;
+ break;
+ case ACCURACY_BLOCK:
+ mQuality = QUALITY_BALANCED_POWER_ACCURACY;
+ break;
+ case POWER_LOW:
+ // fall through
+ case ACCURACY_CITY:
+ mQuality = QUALITY_LOW_POWER;
+ break;
+ case POWER_NONE:
+ mInterval = PASSIVE_INTERVAL;
+ break;
+ default:
+ throw new IllegalArgumentException("invalid quality: " + quality);
+ }
+
return this;
}
/**
- * Returns the quality of the location request.
+ * Returns the quality hint for this location request. The quality hint informs the provider how
+ * it should attempt to manage any accuracy vs power tradeoffs while attempting to satisfy this
+ * location request.
*
- * @return the quality of the location request
- *
- * @hide
+ * @return the desired quality tradeoffs between accuracy and power
*/
- @SystemApi
- public int getQuality() {
- if (mInterval == PASSIVE_INTERVAL) {
- return POWER_NONE;
- } else {
- return mQuality;
- }
+ public @Quality int getQuality() {
+ return mQuality;
}
/**
@@ -749,97 +797,65 @@
if (mProvider != null) {
s.append(mProvider).append(" ");
}
- if (mQuality != POWER_NONE && mQuality != ACCURACY_BLOCK) {
- s.append(qualityToString(mQuality)).append(" ");
- }
if (mInterval != PASSIVE_INTERVAL) {
s.append("@");
TimeUtils.formatDuration(mInterval, s);
+
+ switch (mQuality) {
+ case QUALITY_HIGH_ACCURACY:
+ s.append(" HIGH_ACCURACY");
+ break;
+ case QUALITY_BALANCED_POWER_ACCURACY:
+ s.append(" BALANCED");
+ break;
+ case QUALITY_LOW_POWER:
+ s.append(" LOW_POWER");
+ break;
+ }
} else {
s.append("PASSIVE");
}
if (mExpireAtRealtimeMillis != Long.MAX_VALUE) {
- s.append(" expireAt=").append(TimeUtils.formatRealtime(mExpireAtRealtimeMillis));
+ s.append(", expireAt=").append(TimeUtils.formatRealtime(mExpireAtRealtimeMillis));
}
if (mDurationMillis != Long.MAX_VALUE) {
- s.append(" duration=");
+ s.append(", duration=");
TimeUtils.formatDuration(mDurationMillis, s);
}
if (mMaxUpdates != Integer.MAX_VALUE) {
- s.append(" maxUpdates=").append(mMaxUpdates);
+ s.append(", maxUpdates=").append(mMaxUpdates);
}
if (mMinUpdateIntervalMillis != IMPLICIT_MIN_UPDATE_INTERVAL
&& mMinUpdateIntervalMillis < mInterval) {
- s.append(" minUpdateInterval=");
+ s.append(", minUpdateInterval=");
TimeUtils.formatDuration(mMinUpdateIntervalMillis, s);
}
if (mMinUpdateDistanceMeters > 0.0) {
- s.append(" minUpdateDistance=").append(mMinUpdateDistanceMeters);
+ s.append(", minUpdateDistance=").append(mMinUpdateDistanceMeters);
}
if (mLowPower) {
- s.append(" lowPower");
+ s.append(", lowPower");
}
if (mHideFromAppOps) {
- s.append(" hiddenFromAppOps");
+ s.append(", hiddenFromAppOps");
}
if (mLocationSettingsIgnored) {
- s.append(" locationSettingsIgnored");
+ s.append(", locationSettingsIgnored");
}
- if (mWorkSource != null) {
- s.append(" ").append(mWorkSource);
+ if (mWorkSource != null && !mWorkSource.isEmpty()) {
+ s.append(", ").append(mWorkSource);
}
s.append(']');
return s.toString();
}
- private static String qualityToString(int quality) {
- switch (quality) {
- case ACCURACY_FINE:
- return "ACCURACY_FINE";
- case ACCURACY_BLOCK:
- return "ACCURACY_BLOCK";
- case ACCURACY_CITY:
- return "ACCURACY_CITY";
- case POWER_NONE:
- return "POWER_NONE";
- case POWER_LOW:
- return "POWER_LOW";
- case POWER_HIGH:
- return "POWER_HIGH";
- default:
- return "???";
- }
- }
-
/**
* A builder class for {@link LocationRequest}.
*/
public static final class Builder {
- private static int checkQuality(int quality, boolean allowDeprecated) {
- switch (quality) {
- case ACCURACY_FINE:
- // fall through
- case ACCURACY_BLOCK:
- // fall through
- case ACCURACY_CITY:
- // fall through
- case POWER_LOW:
- // fall through
- case POWER_HIGH:
- return quality;
- case POWER_NONE:
- if (allowDeprecated) {
- return quality;
- }
- // fall through
- default:
- throw new IllegalArgumentException("invalid quality: " + quality);
- }
- }
-
private long mIntervalMillis;
- private int mQuality;
+ private @Quality int mQuality;
private long mDurationMillis;
private int mMaxUpdates;
private long mMinUpdateIntervalMillis;
@@ -857,7 +873,7 @@
// gives us a range check
setIntervalMillis(intervalMillis);
- mQuality = ACCURACY_BLOCK;
+ mQuality = QUALITY_BALANCED_POWER_ACCURACY;
mDurationMillis = Long.MAX_VALUE;
mMaxUpdates = Integer.MAX_VALUE;
mMinUpdateIntervalMillis = IMPLICIT_MIN_UPDATE_INTERVAL;
@@ -885,9 +901,6 @@
// handle edge cases that can only happen with location request that has been modified
// by deprecated SystemApi methods
- if (mQuality == POWER_NONE) {
- mIntervalMillis = PASSIVE_INTERVAL;
- }
if (mIntervalMillis == PASSIVE_INTERVAL
&& mMinUpdateIntervalMillis == IMPLICIT_MIN_UPDATE_INTERVAL) {
// this is the legacy default minimum update interval, so if we're forced to
@@ -914,11 +927,17 @@
}
/**
- * @hide
+ * Sets the request quality. The quality is a hint to providers on how they should weigh
+ * power vs accuracy tradeoffs. High accuracy locations may cost more power to produce, and
+ * lower accuracy locations may cost less power to produce. Defaults to
+ * {@link #QUALITY_BALANCED_POWER_ACCURACY}.
*/
- @SystemApi
- public @NonNull Builder setQuality(int quality) {
- mQuality = checkQuality(quality, false);
+ public @NonNull Builder setQuality(@Quality int quality) {
+ Preconditions.checkArgument(
+ quality == QUALITY_LOW_POWER || quality == QUALITY_BALANCED_POWER_ACCURACY
+ || quality == QUALITY_HIGH_ACCURACY,
+ "quality must be a defined QUALITY constant, not " + quality);
+ mQuality = quality;
return this;
}
@@ -1102,7 +1121,7 @@
return new LocationRequest(
null,
mIntervalMillis,
- mIntervalMillis != PASSIVE_INTERVAL ? mQuality : POWER_NONE,
+ mQuality,
Long.MAX_VALUE,
mDurationMillis,
mMaxUpdates,
diff --git a/location/java/com/android/internal/location/ProviderRequest.java b/location/java/com/android/internal/location/ProviderRequest.java
index fee86ce..00ba552 100644
--- a/location/java/com/android/internal/location/ProviderRequest.java
+++ b/location/java/com/android/internal/location/ProviderRequest.java
@@ -16,10 +16,15 @@
package com.android.internal.location;
+import static android.location.LocationRequest.QUALITY_BALANCED_POWER_ACCURACY;
+import static android.location.LocationRequest.QUALITY_HIGH_ACCURACY;
+import static android.location.LocationRequest.QUALITY_LOW_POWER;
+
import android.annotation.IntRange;
import android.annotation.NonNull;
import android.compat.annotation.UnsupportedAppUsage;
import android.location.LocationRequest;
+import android.location.LocationRequest.Quality;
import android.os.Build;
import android.os.Parcel;
import android.os.Parcelable;
@@ -41,7 +46,7 @@
public static final long INTERVAL_DISABLED = Long.MAX_VALUE;
public static final ProviderRequest EMPTY_REQUEST = new ProviderRequest(
- INTERVAL_DISABLED, false, false, Collections.emptyList(), new WorkSource());
+ INTERVAL_DISABLED, QUALITY_BALANCED_POWER_ACCURACY, false, false, new WorkSource());
@UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, publicAlternatives = "{@link "
+ "ProviderRequest}")
@@ -49,6 +54,7 @@
@UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, publicAlternatives = "{@link "
+ "ProviderRequest}")
public final long interval;
+ private final @Quality int mQuality;
private final boolean mLowPower;
private final boolean mLocationSettingsIgnored;
@UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, publicAlternatives = "{@link "
@@ -56,15 +62,24 @@
public final List<LocationRequest> locationRequests;
private final WorkSource mWorkSource;
- private ProviderRequest(long intervalMillis, boolean lowPower,
- boolean locationSettingsIgnored, @NonNull List<LocationRequest> locationRequests,
- @NonNull WorkSource workSource) {
+ private ProviderRequest(long intervalMillis, @Quality int quality, boolean lowPower,
+ boolean locationSettingsIgnored, @NonNull WorkSource workSource) {
reportLocation = intervalMillis != INTERVAL_DISABLED;
interval = intervalMillis;
+ mQuality = quality;
mLowPower = lowPower;
mLocationSettingsIgnored = locationSettingsIgnored;
- this.locationRequests = locationRequests;
- mWorkSource = workSource;
+ if (intervalMillis != INTERVAL_DISABLED) {
+ locationRequests = Collections.singletonList(new LocationRequest.Builder(intervalMillis)
+ .setQuality(quality)
+ .setLowPower(lowPower)
+ .setLocationSettingsIgnored(locationSettingsIgnored)
+ .setWorkSource(workSource)
+ .build());
+ } else {
+ locationRequests = Collections.emptyList();
+ }
+ mWorkSource = Objects.requireNonNull(workSource);
}
/**
@@ -84,6 +99,15 @@
}
/**
+ * The quality hint for this location request. The quality hint informs the provider how it
+ * should attempt to manage any accuracy vs power tradeoffs while attempting to satisfy this
+ * provider request.
+ */
+ public @Quality int getQuality() {
+ return mQuality;
+ }
+
+ /**
* Whether any applicable hardware low power modes should be used to satisfy this request.
*/
public boolean isLowPower() {
@@ -100,13 +124,6 @@
}
/**
- * The full list of location requests contributing to this provider request.
- */
- public @NonNull List<LocationRequest> getLocationRequests() {
- return locationRequests;
- }
-
- /**
* The power blame for this provider request.
*/
public @NonNull WorkSource getWorkSource() {
@@ -117,13 +134,17 @@
new Parcelable.Creator<ProviderRequest>() {
@Override
public ProviderRequest createFromParcel(Parcel in) {
- return new ProviderRequest(
- /* intervalMillis= */ in.readLong(),
- /* lowPower= */ in.readBoolean(),
- /* locationSettingsIgnored= */ in.readBoolean(),
- /* locationRequests= */
- in.createTypedArrayList(LocationRequest.CREATOR),
- /* workSource= */ in.readTypedObject(WorkSource.CREATOR));
+ long intervalMillis = in.readLong();
+ if (intervalMillis == INTERVAL_DISABLED) {
+ return EMPTY_REQUEST;
+ } else {
+ return new ProviderRequest(
+ intervalMillis,
+ /* quality= */ in.readInt(),
+ /* lowPower= */ in.readBoolean(),
+ /* locationSettingsIgnored= */ in.readBoolean(),
+ /* workSource= */ in.readTypedObject(WorkSource.CREATOR));
+ }
}
@Override
@@ -140,10 +161,12 @@
@Override
public void writeToParcel(Parcel parcel, int flags) {
parcel.writeLong(interval);
- parcel.writeBoolean(mLowPower);
- parcel.writeBoolean(mLocationSettingsIgnored);
- parcel.writeTypedList(locationRequests);
- parcel.writeTypedObject(mWorkSource, flags);
+ if (interval != INTERVAL_DISABLED) {
+ parcel.writeInt(mQuality);
+ parcel.writeBoolean(mLowPower);
+ parcel.writeBoolean(mLocationSettingsIgnored);
+ parcel.writeTypedObject(mWorkSource, flags);
+ }
}
@Override
@@ -160,16 +183,16 @@
return that.interval == INTERVAL_DISABLED;
} else {
return interval == that.interval
+ && mQuality == that.mQuality
&& mLowPower == that.mLowPower
&& mLocationSettingsIgnored == that.mLocationSettingsIgnored
- && locationRequests.equals(that.locationRequests)
&& mWorkSource.equals(that.mWorkSource);
}
}
@Override
public int hashCode() {
- return Objects.hash(interval, mWorkSource);
+ return Objects.hash(interval, mQuality, mWorkSource);
}
@Override
@@ -179,6 +202,13 @@
if (interval != INTERVAL_DISABLED) {
s.append("@");
TimeUtils.formatDuration(interval, s);
+ if (mQuality != QUALITY_BALANCED_POWER_ACCURACY) {
+ if (mQuality == QUALITY_HIGH_ACCURACY) {
+ s.append(", HIGH_ACCURACY");
+ } else if (mQuality == QUALITY_LOW_POWER) {
+ s.append(", LOW_POWER");
+ }
+ }
if (mLowPower) {
s.append(", lowPower");
}
@@ -200,9 +230,9 @@
*/
public static class Builder {
private long mIntervalMillis = INTERVAL_DISABLED;
+ private int mQuality = QUALITY_BALANCED_POWER_ACCURACY;
private boolean mLowPower;
private boolean mLocationSettingsIgnored;
- private List<LocationRequest> mLocationRequests = Collections.emptyList();
private WorkSource mWorkSource = new WorkSource();
/**
@@ -216,6 +246,20 @@
}
/**
+ * Sets the request quality. The quality is a hint to providers on how they should weigh
+ * power vs accuracy tradeoffs. High accuracy locations may cost more power to produce, and
+ * lower accuracy locations may cost less power to produce. Defaults to
+ * {@link LocationRequest#QUALITY_BALANCED_POWER_ACCURACY}.
+ */
+ public @NonNull Builder setQuality(@Quality int quality) {
+ Preconditions.checkArgument(
+ quality == QUALITY_LOW_POWER || quality == QUALITY_BALANCED_POWER_ACCURACY
+ || quality == QUALITY_HIGH_ACCURACY);
+ mQuality = quality;
+ return this;
+ }
+
+ /**
* Sets whether hardware low power mode should be used. False by default.
*/
public @NonNull Builder setLowPower(boolean lowPower) {
@@ -232,15 +276,6 @@
}
/**
- * Sets the {@link LocationRequest}s associated with this request. Empty by default.
- */
- public @NonNull Builder setLocationRequests(
- @NonNull List<LocationRequest> locationRequests) {
- this.mLocationRequests = Objects.requireNonNull(locationRequests);
- return this;
- }
-
- /**
* Sets the work source for power blame. Empty by default.
*/
public @NonNull Builder setWorkSource(@NonNull WorkSource workSource) {
@@ -255,8 +290,8 @@
if (mIntervalMillis == INTERVAL_DISABLED) {
return EMPTY_REQUEST;
} else {
- return new ProviderRequest(mIntervalMillis, mLowPower, mLocationSettingsIgnored,
- mLocationRequests, mWorkSource);
+ return new ProviderRequest(mIntervalMillis, mQuality, mLowPower,
+ mLocationSettingsIgnored, mWorkSource);
}
}
}
diff --git a/location/lib/api/current.txt b/location/lib/api/current.txt
index f43eb63..80636c6 100644
--- a/location/lib/api/current.txt
+++ b/location/lib/api/current.txt
@@ -29,18 +29,18 @@
field public static final String FUSED_PROVIDER = "fused";
}
- public final class LocationRequestUnbundled {
- method public long getFastestInterval();
- method public long getInterval();
- method public int getQuality();
- method public float getSmallestDisplacement();
- method public boolean isLocationSettingsIgnored();
- field public static final int ACCURACY_BLOCK = 102; // 0x66
- field public static final int ACCURACY_CITY = 104; // 0x68
- field public static final int ACCURACY_FINE = 100; // 0x64
- field public static final int POWER_HIGH = 203; // 0xcb
- field public static final int POWER_LOW = 201; // 0xc9
- field public static final int POWER_NONE = 200; // 0xc8
+ @Deprecated public final class LocationRequestUnbundled {
+ method @Deprecated public long getFastestInterval();
+ method @Deprecated public long getInterval();
+ method @Deprecated @android.location.LocationRequest.Quality public int getQuality();
+ method @Deprecated public float getSmallestDisplacement();
+ method @Deprecated public boolean isLocationSettingsIgnored();
+ field @Deprecated public static final int ACCURACY_BLOCK = 102; // 0x66
+ field @Deprecated public static final int ACCURACY_CITY = 104; // 0x68
+ field @Deprecated public static final int ACCURACY_FINE = 100; // 0x64
+ field @Deprecated public static final int POWER_HIGH = 203; // 0xcb
+ field @Deprecated public static final int POWER_LOW = 201; // 0xc9
+ field @Deprecated public static final int POWER_NONE = 200; // 0xc8
}
public final class ProviderPropertiesUnbundled {
@@ -49,7 +49,8 @@
public final class ProviderRequestUnbundled {
method public long getInterval();
- method @NonNull public java.util.List<com.android.location.provider.LocationRequestUnbundled> getLocationRequests();
+ method @Deprecated @NonNull public java.util.List<com.android.location.provider.LocationRequestUnbundled> getLocationRequests();
+ method @android.location.LocationRequest.Quality @RequiresApi(android.os.Build.VERSION_CODES.S) public int getQuality();
method public boolean getReportLocation();
method @NonNull @RequiresApi(android.os.Build.VERSION_CODES.S) public android.os.WorkSource getWorkSource();
method @RequiresApi(android.os.Build.VERSION_CODES.Q) public boolean isLocationSettingsIgnored();
diff --git a/location/lib/java/com/android/location/provider/LocationRequestUnbundled.java b/location/lib/java/com/android/location/provider/LocationRequestUnbundled.java
index 92e05ef..0e7c633 100644
--- a/location/lib/java/com/android/location/provider/LocationRequestUnbundled.java
+++ b/location/lib/java/com/android/location/provider/LocationRequestUnbundled.java
@@ -17,6 +17,7 @@
package com.android.location.provider;
import android.location.LocationRequest;
+import android.location.LocationRequest.Quality;
/**
* This class is an interface to LocationRequests for unbundled applications.
@@ -24,55 +25,50 @@
* <p>IMPORTANT: This class is effectively a public API for unbundled
* applications, and must remain API stable. See README.txt in the root
* of this package for more information.
+ *
+ * @deprecated Do not use.
*/
+@Deprecated
public final class LocationRequestUnbundled {
+
/**
- * Returned by {@link #getQuality} when requesting the most accurate locations available.
- *
- * <p>This may be up to 1 meter accuracy, although this is implementation dependent.
+ * @deprecated Use {@link LocationRequest#QUALITY_HIGH_ACCURACY} instead.
*/
+ @Deprecated
public static final int ACCURACY_FINE = LocationRequest.ACCURACY_FINE;
/**
- * Returned by {@link #getQuality} when requesting "block" level accuracy.
- *
- * <p>Block level accuracy is considered to be about 100 meter accuracy,
- * although this is implementation dependent. Using a coarse accuracy
- * such as this often consumes less power.
+ * @deprecated Use {@link LocationRequest#QUALITY_BALANCED_POWER_ACCURACY} instead.
*/
+ @Deprecated
public static final int ACCURACY_BLOCK = LocationRequest.ACCURACY_BLOCK;
+
/**
- * Returned by {@link #getQuality} when requesting "city" level accuracy.
- *
- * <p>City level accuracy is considered to be about 10km accuracy,
- * although this is implementation dependent. Using a coarse accuracy
- * such as this often consumes less power.
+ * @deprecated Use {@link LocationRequest#QUALITY_LOW_POWER} instead.
*/
+ @Deprecated
public static final int ACCURACY_CITY = LocationRequest.ACCURACY_CITY;
+
/**
- * Returned by {@link #getQuality} when requiring no direct power impact (passive locations).
- *
- * <p>This location request will not trigger any active location requests,
- * but will receive locations triggered by other applications. Your application
- * will not receive any direct power blame for location work.
+ * @deprecated Do not use.
*/
+ @Deprecated
public static final int POWER_NONE = LocationRequest.POWER_NONE;
- /**
- * Returned by {@link #getQuality} when requesting low power impact.
- *
- * <p>This location request will avoid high power location work where
- * possible.
- */
- public static final int POWER_LOW = LocationRequest.POWER_LOW;
/**
- * Returned by {@link #getQuality} when allowing high power consumption for location.
- *
- * <p>This location request will allow high power location work.
+ * @deprecated Use {@link LocationRequest#QUALITY_LOW_POWER} instead.
*/
+ @Deprecated
+ public static final int POWER_LOW = LocationRequest.POWER_LOW;
+
+
+ /**
+ * @deprecated Use {@link LocationRequest#QUALITY_BALANCED_POWER_ACCURACY} instead.
+ */
+ @Deprecated
public static final int POWER_HIGH = LocationRequest.POWER_HIGH;
private final LocationRequest delegate;
@@ -102,9 +98,9 @@
/**
* Get the quality of the request.
*
- * @return an accuracy or power constant
+ * @return a {@link LocationRequest} QUALITY_* constant
*/
- public int getQuality() {
+ public @Quality int getQuality() {
return delegate.getQuality();
}
diff --git a/location/lib/java/com/android/location/provider/ProviderRequestUnbundled.java b/location/lib/java/com/android/location/provider/ProviderRequestUnbundled.java
index 6f5fcc7..f7bac74 100644
--- a/location/lib/java/com/android/location/provider/ProviderRequestUnbundled.java
+++ b/location/lib/java/com/android/location/provider/ProviderRequestUnbundled.java
@@ -25,7 +25,7 @@
import com.android.internal.location.ProviderRequest;
-import java.util.ArrayList;
+import java.util.Collections;
import java.util.List;
/**
@@ -57,6 +57,16 @@
}
/**
+ * The quality hint for this location request. The quality hint informs the provider how it
+ * should attempt to manage any accuracy vs power tradeoffs while attempting to satisfy this
+ * provider request.
+ */
+ @RequiresApi(Build.VERSION_CODES.S)
+ public @LocationRequest.Quality int getQuality() {
+ return mRequest.getQuality();
+ }
+
+ /**
* The interval at which a provider should report location. Will return
* {@link #INTERVAL_DISABLED} for an inactive request.
*/
@@ -84,14 +94,22 @@
/**
* The full list of location requests contributing to this provider request.
+ *
+ * @deprecated Do not use.
*/
+ @Deprecated
public @NonNull List<LocationRequestUnbundled> getLocationRequests() {
- List<LocationRequestUnbundled> result = new ArrayList<>(
- mRequest.getLocationRequests().size());
- for (LocationRequest r : mRequest.getLocationRequests()) {
- result.add(new LocationRequestUnbundled(r));
+ if (!mRequest.isActive()) {
+ return Collections.emptyList();
}
- return result;
+
+ return Collections.singletonList(new LocationRequestUnbundled(
+ new LocationRequest.Builder(mRequest.getIntervalMillis())
+ .setQuality(mRequest.getQuality())
+ .setLowPower(mRequest.isLowPower())
+ .setLocationSettingsIgnored(mRequest.isLocationSettingsIgnored())
+ .setWorkSource(mRequest.getWorkSource())
+ .build()));
}
/**
diff --git a/media/java/android/media/tv/TunedInfo.java b/media/java/android/media/tv/TunedInfo.java
index 6fc5784..6199c89 100644
--- a/media/java/android/media/tv/TunedInfo.java
+++ b/media/java/android/media/tv/TunedInfo.java
@@ -19,6 +19,7 @@
import android.annotation.IntDef;
import android.annotation.NonNull;
import android.annotation.Nullable;
+import android.annotation.SystemApi;
import android.net.Uri;
import android.os.Parcel;
import android.os.Parcelable;
@@ -35,6 +36,7 @@
* or pass-through input.
* @hide
*/
+@SystemApi
public final class TunedInfo implements Parcelable {
static final String TAG = "TunedInfo";
diff --git a/media/java/android/media/tv/TvInputManager.java b/media/java/android/media/tv/TvInputManager.java
index 73539fb..e9959be 100644
--- a/media/java/android/media/tv/TvInputManager.java
+++ b/media/java/android/media/tv/TvInputManager.java
@@ -906,8 +906,8 @@
* @param tunedInfos a list of {@link TunedInfo} objects of new tuned information.
* @hide
*/
- public void onCurrentTunedInfosUpdated(
- @NonNull List<TunedInfo> tunedInfos) {
+ @SystemApi
+ public void onCurrentTunedInfosUpdated(@NonNull List<TunedInfo> tunedInfos) {
}
}
@@ -969,7 +969,7 @@
});
}
- public void onCurrentTunedInfosUpdated(final List<TunedInfo> currentTunedInfos) {
+ public void postCurrentTunedInfosUpdated(final List<TunedInfo> currentTunedInfos) {
mHandler.post(new Runnable() {
@Override
public void run() {
@@ -1286,7 +1286,7 @@
public void onCurrentTunedInfosUpdated(List<TunedInfo> currentTunedInfos) {
synchronized (mLock) {
for (TvInputCallbackRecord record : mCallbackRecords) {
- record.onCurrentTunedInfosUpdated(currentTunedInfos);
+ record.postCurrentTunedInfosUpdated(currentTunedInfos);
}
}
}
@@ -1988,6 +1988,7 @@
* {@link TunedInfo#getChannelUri()} returns {@code null}.
* @hide
*/
+ @SystemApi
@RequiresPermission("com.android.providers.tv.permission.ACCESS_WATCHED_PROGRAMS")
@NonNull
public List<TunedInfo> getCurrentTunedInfos() {
diff --git a/media/java/android/media/tv/tuner/Tuner.java b/media/java/android/media/tv/tuner/Tuner.java
index 27a49a7..3252c90 100644
--- a/media/java/android/media/tv/tuner/Tuner.java
+++ b/media/java/android/media/tv/tuner/Tuner.java
@@ -122,10 +122,25 @@
android.hardware.tv.tuner.V1_1.Constants.Constant
.INVALID_MMTP_RECORD_EVENT_MPT_SEQUENCE_NUM;
/**
+ * Invalid local transport stream id.
+ *
+ * <p>Returned by {@link #linkFrontendToCiCam(int)} when the requested failed
+ * or the hal implementation does not support the operation.
+ *
+ * @see #linkFrontendToCiCam(int)
+ */
+ public static final int INVALID_LTS_ID =
+ android.hardware.tv.tuner.V1_1.Constants.Constant.INVALID_LTS_ID;
+ /**
* Invalid 64-bit filter ID.
*/
public static final long INVALID_FILTER_ID_64BIT =
android.hardware.tv.tuner.V1_1.Constants.Constant64Bit.INVALID_FILTER_ID_64BIT;
+ /**
+ * Invalid frequency that is used as the default frontend frequency setting.
+ */
+ public static final int INVALID_FRONTEND_SETTING_FREQUENCY =
+ android.hardware.tv.tuner.V1_1.Constants.Constant.INVALID_FRONTEND_SETTING_FREQUENCY;
/** @hide */
@IntDef(prefix = "SCAN_TYPE_", value = {SCAN_TYPE_UNDEFINED, SCAN_TYPE_AUTO, SCAN_TYPE_BLIND})
@@ -475,7 +490,9 @@
private native Integer nativeGetAvSyncHwId(Filter filter);
private native Long nativeGetAvSyncTime(int avSyncId);
private native int nativeConnectCiCam(int ciCamId);
+ private native int nativeLinkCiCam(int ciCamId);
private native int nativeDisconnectCiCam();
+ private native int nativeUnlinkCiCam(int ciCamId);
private native FrontendInfo nativeGetFrontendInfo(int id);
private native Filter nativeOpenFilter(int type, int subType, long bufferSize);
private native TimeFilter nativeOpenTimeFilter();
@@ -798,6 +815,33 @@
}
/**
+ * Link Conditional Access Modules (CAM) Frontend to support Common Interface (CI) by-pass mode.
+ *
+ * <p>It is used by the client to link CI-CAM to a Frontend. CI by-pass mode requires that
+ * the CICAM also receives the TS concurrently from the frontend when the Demux is receiving
+ * the TS directly from the frontend.
+ *
+ * <p>Use {@link #unlinkFrontendToCicam(int)} to disconnect.
+ *
+ * <p>This API is only supported by Tuner HAL 1.1 or higher. Unsupported version would cause
+ * no-op and return {@link INVALID_LTS_ID}. Use {@link TunerVersionChecker.getTunerVersion()} to
+ * check the version.
+ *
+ * @param ciCamId specify CI-CAM Id to link.
+ * @return Local transport stream id when connection is successfully established. Failed
+ * operation returns {@link INVALID_LTS_ID}.
+ */
+ public int linkFrontendToCiCam(int ciCamId) {
+ if (TunerVersionChecker.checkHigherOrEqualVersionTo(TunerVersionChecker.TUNER_VERSION_1_1,
+ "linkFrontendToCiCam")) {
+ if (checkResource(TunerResourceManager.TUNER_RESOURCE_TYPE_FRONTEND)) {
+ return nativeLinkCiCam(ciCamId);
+ }
+ }
+ return INVALID_LTS_ID;
+ }
+
+ /**
* Disconnects Conditional Access Modules (CAM)
*
* <p>The demux will use the output from the frontend as the input after this call.
@@ -813,6 +857,28 @@
}
/**
+ * Unlink Conditional Access Modules (CAM) Frontend.
+ *
+ * <p>It is used by the client to unlink CI-CAM to a Frontend.
+ *
+ * <p>This API is only supported by Tuner HAL 1.1 or higher. Unsupported version would cause
+ * no-op. Use {@link TunerVersionChecker.getTunerVersion()} to check the version.
+ *
+ * @param ciCamId specify CI-CAM Id to unlink.
+ * @return result status of the operation.
+ */
+ @Result
+ public int unlinkFrontendToCiCam(int ciCamId) {
+ if (TunerVersionChecker.checkHigherOrEqualVersionTo(TunerVersionChecker.TUNER_VERSION_1_1,
+ "unlinkFrontendToCiCam")) {
+ if (checkResource(TunerResourceManager.TUNER_RESOURCE_TYPE_FRONTEND)) {
+ return nativeUnlinkCiCam(ciCamId);
+ }
+ }
+ return RESULT_UNAVAILABLE;
+ }
+
+ /**
* Gets the frontend information.
*
* @return The frontend information. {@code null} if the operation failed.
diff --git a/media/java/android/media/tv/tuner/filter/IpFilterConfiguration.java b/media/java/android/media/tv/tuner/filter/IpFilterConfiguration.java
index f54b686..2649fcf 100644
--- a/media/java/android/media/tv/tuner/filter/IpFilterConfiguration.java
+++ b/media/java/android/media/tv/tuner/filter/IpFilterConfiguration.java
@@ -20,6 +20,7 @@
import android.annotation.Nullable;
import android.annotation.Size;
import android.annotation.SystemApi;
+import android.media.tv.tuner.TunerVersionChecker;
/**
* Filter configuration for a IP filter.
@@ -28,20 +29,28 @@
*/
@SystemApi
public final class IpFilterConfiguration extends FilterConfiguration {
+ /**
+ * Undefined filter type.
+ */
+ public static final int INVALID_IP_FILTER_CONTEXT_ID =
+ android.hardware.tv.tuner.V1_1.Constants.Constant.INVALID_IP_FILTER_CONTEXT_ID;
+
private final byte[] mSrcIpAddress;
private final byte[] mDstIpAddress;
private final int mSrcPort;
private final int mDstPort;
private final boolean mPassthrough;
+ private final int mIpFilterContextId;
private IpFilterConfiguration(Settings settings, byte[] srcAddr, byte[] dstAddr, int srcPort,
- int dstPort, boolean passthrough) {
+ int dstPort, boolean passthrough, int ipCid) {
super(settings);
mSrcIpAddress = srcAddr;
mDstIpAddress = dstAddr;
mSrcPort = srcPort;
mDstPort = dstPort;
mPassthrough = passthrough;
+ mIpFilterContextId = ipCid;
}
@Override
@@ -86,6 +95,15 @@
public boolean isPassthrough() {
return mPassthrough;
}
+ /**
+ * Gets the ip filter context id. Default value is {@link #INVALID_IP_FILTER_CONTEXT_ID}.
+ *
+ * <p>This API is only supported by Tuner HAL 1.1 or higher. Unsupported version would return
+ * default value. Use {@link TunerVersionChecker.getTunerVersion()} to check the version.
+ */
+ public int getIpFilterContextId() {
+ return mIpFilterContextId;
+ }
/**
* Creates a builder for {@link IpFilterConfiguration}.
@@ -105,6 +123,7 @@
private int mDstPort = 0;
private boolean mPassthrough = false;
private Settings mSettings;
+ private int mIpCid = INVALID_IP_FILTER_CONTEXT_ID;
private Builder() {
}
@@ -170,6 +189,21 @@
}
/**
+ * Sets the ip filter context id. Default value is {@link #INVALID_IP_FILTER_CONTEXT_ID}.
+ *
+ * <p>This API is only supported by Tuner HAL 1.1 or higher. Unsupported version would cause
+ * no-op. Use {@link TunerVersionChecker.getTunerVersion()} to check the version.
+ */
+ @NonNull
+ public Builder setIpFilterContextId(int ipContextId) {
+ if (TunerVersionChecker.checkHigherOrEqualVersionTo(
+ TunerVersionChecker.TUNER_VERSION_1_1, "setIpFilterContextId")) {
+ mIpCid = ipContextId;
+ }
+ return this;
+ }
+
+ /**
* Builds a {@link IpFilterConfiguration} object.
*/
@NonNull
@@ -180,8 +214,8 @@
"The lengths of src and dst IP address must be 4 or 16 and must be the same."
+ "srcLength=" + ipAddrLength + ", dstLength=" + mDstIpAddress.length);
}
- return new IpFilterConfiguration(
- mSettings, mSrcIpAddress, mDstIpAddress, mSrcPort, mDstPort, mPassthrough);
+ return new IpFilterConfiguration(mSettings, mSrcIpAddress, mDstIpAddress, mSrcPort,
+ mDstPort, mPassthrough, mIpCid);
}
}
}
diff --git a/media/java/android/media/tv/tuner/frontend/AnalogFrontendSettings.java b/media/java/android/media/tv/tuner/frontend/AnalogFrontendSettings.java
index 1d36da3..c6a5bb0 100644
--- a/media/java/android/media/tv/tuner/frontend/AnalogFrontendSettings.java
+++ b/media/java/android/media/tv/tuner/frontend/AnalogFrontendSettings.java
@@ -21,6 +21,7 @@
import android.annotation.NonNull;
import android.annotation.SystemApi;
import android.hardware.tv.tuner.V1_0.Constants;
+import android.media.tv.tuner.TunerVersionChecker;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
@@ -164,9 +165,32 @@
*/
public static final int SIF_L_PRIME = Constants.FrontendAnalogSifStandard.L_PRIME;
+ /** @hide */
+ @IntDef(prefix = "AFT_FLAG_",
+ value = {AFT_FLAG_UNDEFINED, AFT_FLAG_TRUE, AFT_FLAG_FALSE})
+ @Retention(RetentionPolicy.SOURCE)
+ public @interface AftFlag {}
+
+ /**
+ * Aft flag is not defined.
+ */
+ public static final int AFT_FLAG_UNDEFINED =
+ android.hardware.tv.tuner.V1_1.Constants.FrontendAnalogAftFlag.UNDEFINED;
+ /**
+ * Aft flag is set true.
+ */
+ public static final int AFT_FLAG_TRUE =
+ android.hardware.tv.tuner.V1_1.Constants.FrontendAnalogAftFlag.AFT_TRUE;
+ /**
+ * Aft flag is not set.
+ */
+ public static final int AFT_FLAG_FALSE =
+ android.hardware.tv.tuner.V1_1.Constants.FrontendAnalogAftFlag.AFT_FALSE;
+
private final int mSignalType;
private final int mSifStandard;
+ private final int mAftFlag;
@Override
public int getType() {
@@ -191,6 +215,14 @@
}
/**
+ * Gets AFT flag.
+ */
+ @AftFlag
+ public int getAftFlag() {
+ return mAftFlag;
+ }
+
+ /**
* Creates a builder for {@link AnalogFrontendSettings}.
*/
@NonNull
@@ -198,10 +230,11 @@
return new Builder();
}
- private AnalogFrontendSettings(int frequency, int signalType, int sifStandard) {
+ private AnalogFrontendSettings(int frequency, int signalType, int sifStandard, int aftFlag) {
super(frequency);
mSignalType = signalType;
mSifStandard = sifStandard;
+ mAftFlag = aftFlag;
}
/**
@@ -211,6 +244,7 @@
private int mFrequency = 0;
private int mSignalType = SIGNAL_TYPE_UNDEFINED;
private int mSifStandard = SIF_UNDEFINED;
+ private int mAftFlag = AFT_FLAG_UNDEFINED;
private Builder() {}
@@ -227,6 +261,24 @@
}
/**
+ * Set Aft flag.
+ *
+ * <p>This API is only supported by Tuner HAL 1.1 or higher. Unsupported version would cause
+ * no-op. Use {@link TunerVersionChecker.getTunerVersion()} to check the version.
+ *
+ * @param aftFlag the value to set the aft flag. The default value is
+ * {@link #AFT_FLAG_UNDEFINED}.
+ */
+ @NonNull
+ public Builder setAftFlag(@AftFlag int aftFlag) {
+ if (TunerVersionChecker.checkHigherOrEqualVersionTo(
+ TunerVersionChecker.TUNER_VERSION_1_1, "setAftFlag")) {
+ mAftFlag = aftFlag;
+ }
+ return this;
+ }
+
+ /**
* Sets analog signal type.
*
* <p>Default value is {@link #SIGNAL_TYPE_UNDEFINED}.
@@ -253,7 +305,7 @@
*/
@NonNull
public AnalogFrontendSettings build() {
- return new AnalogFrontendSettings(mFrequency, mSignalType, mSifStandard);
+ return new AnalogFrontendSettings(mFrequency, mSignalType, mSifStandard, mAftFlag);
}
}
}
diff --git a/media/java/android/media/tv/tuner/frontend/Atsc3FrontendSettings.java b/media/java/android/media/tv/tuner/frontend/Atsc3FrontendSettings.java
index f9eabc5..ed1ce2d 100644
--- a/media/java/android/media/tv/tuner/frontend/Atsc3FrontendSettings.java
+++ b/media/java/android/media/tv/tuner/frontend/Atsc3FrontendSettings.java
@@ -377,8 +377,8 @@
*/
@NonNull
public Atsc3FrontendSettings build() {
- return new Atsc3FrontendSettings(
- mFrequency, mBandwidth, mDemodOutputFormat, mPlpSettings);
+ return new Atsc3FrontendSettings(mFrequency, mBandwidth, mDemodOutputFormat,
+ mPlpSettings);
}
}
diff --git a/media/java/android/media/tv/tuner/frontend/DvbcFrontendSettings.java b/media/java/android/media/tv/tuner/frontend/DvbcFrontendSettings.java
index 271e91e..6732686 100644
--- a/media/java/android/media/tv/tuner/frontend/DvbcFrontendSettings.java
+++ b/media/java/android/media/tv/tuner/frontend/DvbcFrontendSettings.java
@@ -21,6 +21,8 @@
import android.annotation.NonNull;
import android.annotation.SystemApi;
import android.hardware.tv.tuner.V1_0.Constants;
+import android.media.tv.tuner.TunerVersionChecker;
+import android.media.tv.tuner.frontend.FrontendSettings.FrontendSpectralInversion;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
@@ -140,6 +142,74 @@
public static final int SPECTRAL_INVERSION_INVERTED =
Constants.FrontendDvbcSpectralInversion.INVERTED;
+ /** @hide */
+ @IntDef(flag = true,
+ prefix = "TIME_INTERLEAVE_MODE_",
+ value = {TIME_INTERLEAVE_MODE_UNDEFINED, TIME_INTERLEAVE_MODE_AUTO,
+ TIME_INTERLEAVE_MODE_128_1_0, TIME_INTERLEAVE_MODE_128_1_1,
+ TIME_INTERLEAVE_MODE_64_2, TIME_INTERLEAVE_MODE_32_4,
+ TIME_INTERLEAVE_MODE_16_8, TIME_INTERLEAVE_MODE_8_16,
+ TIME_INTERLEAVE_MODE_128_2, TIME_INTERLEAVE_MODE_128_3,
+ TIME_INTERLEAVE_MODE_128_4})
+ @Retention(RetentionPolicy.SOURCE)
+ public @interface TimeInterleaveMode {}
+
+ /**
+ * Time interleave mode undefined.
+ */
+ public static final int TIME_INTERLEAVE_MODE_UNDEFINED =
+ android.hardware.tv.tuner.V1_1.Constants.FrontendCableTimeInterleaveMode.UNDEFINED;
+ /**
+ * Hardware is able to detect and set Time Interleave Mode automatically.
+ */
+ public static final int TIME_INTERLEAVE_MODE_AUTO =
+ android.hardware.tv.tuner.V1_1.Constants.FrontendCableTimeInterleaveMode.AUTO;
+ /**
+ * 128/1/0 Time Interleave Mode.
+ */
+ public static final int TIME_INTERLEAVE_MODE_128_1_0 = android.hardware.tv.tuner.V1_1.Constants
+ .FrontendCableTimeInterleaveMode.INTERLEAVING_128_1_0;
+ /**
+ * 128/1/1 Time Interleave Mode.
+ */
+ public static final int TIME_INTERLEAVE_MODE_128_1_1 = android.hardware.tv.tuner.V1_1.Constants
+ .FrontendCableTimeInterleaveMode.INTERLEAVING_128_1_1;
+ /**
+ * 64/2 Time Interleave Mode.
+ */
+ public static final int TIME_INTERLEAVE_MODE_64_2 = android.hardware.tv.tuner.V1_1.Constants
+ .FrontendCableTimeInterleaveMode.INTERLEAVING_64_2;
+ /**
+ * 32/4 Time Interleave Mode.
+ */
+ public static final int TIME_INTERLEAVE_MODE_32_4 = android.hardware.tv.tuner.V1_1.Constants
+ .FrontendCableTimeInterleaveMode.INTERLEAVING_32_4;
+ /**
+ * 16/8 Time Interleave Mode.
+ */
+ public static final int TIME_INTERLEAVE_MODE_16_8 = android.hardware.tv.tuner.V1_1.Constants
+ .FrontendCableTimeInterleaveMode.INTERLEAVING_16_8;
+ /**
+ * 8/16 Time Interleave Mode.
+ */
+ public static final int TIME_INTERLEAVE_MODE_8_16 = android.hardware.tv.tuner.V1_1.Constants
+ .FrontendCableTimeInterleaveMode.INTERLEAVING_8_16;
+ /**
+ * 128/2 Time Interleave Mode.
+ */
+ public static final int TIME_INTERLEAVE_MODE_128_2 = android.hardware.tv.tuner.V1_1.Constants
+ .FrontendCableTimeInterleaveMode.INTERLEAVING_128_2;
+ /**
+ * 128/3 Time Interleave Mode.
+ */
+ public static final int TIME_INTERLEAVE_MODE_128_3 = android.hardware.tv.tuner.V1_1.Constants
+ .FrontendCableTimeInterleaveMode.INTERLEAVING_128_3;
+ /**
+ * 128/4 Time Interleave Mode.
+ */
+ public static final int TIME_INTERLEAVE_MODE_128_4 = android.hardware.tv.tuner.V1_1.Constants
+ .FrontendCableTimeInterleaveMode.INTERLEAVING_128_4;
+
private final int mModulation;
private final long mInnerFec;
@@ -147,9 +217,11 @@
private final int mOuterFec;
private final int mAnnex;
private final int mSpectralInversion;
+ // Dvbc time interleave mode is only supported in Tuner 1.1 or higher.
+ private final int mInterleaveMode;
private DvbcFrontendSettings(int frequency, int modulation, long innerFec, int symbolRate,
- int outerFec, int annex, int spectralInversion) {
+ int outerFec, int annex, int spectralInversion, int interleaveMode) {
super(frequency);
mModulation = modulation;
mInnerFec = innerFec;
@@ -157,6 +229,7 @@
mOuterFec = outerFec;
mAnnex = annex;
mSpectralInversion = spectralInversion;
+ mInterleaveMode = interleaveMode;
}
/**
@@ -196,10 +269,17 @@
/**
* Gets Spectral Inversion.
*/
- @SpectralInversion
+ @FrontendSpectralInversion
public int getSpectralInversion() {
return mSpectralInversion;
}
+ /**
+ * Gets Time Interleave Mode.
+ */
+ @TimeInterleaveMode
+ public int getTimeInterleaveMode() {
+ return mInterleaveMode;
+ }
/**
* Creates a builder for {@link DvbcFrontendSettings}.
@@ -219,7 +299,8 @@
private int mSymbolRate = 0;
private int mOuterFec = OUTER_FEC_UNDEFINED;
private int mAnnex = ANNEX_UNDEFINED;
- private int mSpectralInversion = SPECTRAL_INVERSION_UNDEFINED;
+ private int mSpectralInversion = FrontendSettings.FRONTEND_SPECTRAL_INVERSION_UNDEFINED;
+ private int mInterleaveMode = TIME_INTERLEAVE_MODE_UNDEFINED;
private Builder() {
}
@@ -289,13 +370,30 @@
/**
* Sets Spectral Inversion.
*
- * <p>Default value is {@link #SPECTRAL_INVERSION_UNDEFINED}.
+ * <p>Default value is {@link FrontendSettings#FRONTEND_SPECTRAL_INVERSION_UNDEFINED}.
*/
@NonNull
- public Builder setSpectralInversion(@SpectralInversion int spectralInversion) {
+ public Builder setSpectralInversion(@FrontendSpectralInversion int spectralInversion) {
mSpectralInversion = spectralInversion;
return this;
}
+ /**
+ * Set the time interleave mode.
+ *
+ * <p>This API is only supported by Tuner HAL 1.1 or higher. Unsupported version would cause
+ * no-op. Use {@link TunerVersionChecker.getTunerVersion()} to check the version.
+ *
+ * @param interleaveMode the value to set as the time interleave mode. Default value is
+ * {@link #TIME_INTERLEAVE_MODE_UNDEFINED}.
+ */
+ @NonNull
+ public Builder setTimeInterleaveMode(@TimeInterleaveMode int interleaveMode) {
+ if (TunerVersionChecker.checkHigherOrEqualVersionTo(
+ TunerVersionChecker.TUNER_VERSION_1_1, "setTimeInterleaveMode")) {
+ mInterleaveMode = interleaveMode;
+ }
+ return this;
+ }
/**
* Builds a {@link DvbcFrontendSettings} object.
@@ -303,7 +401,7 @@
@NonNull
public DvbcFrontendSettings build() {
return new DvbcFrontendSettings(mFrequency, mModulation, mInnerFec, mSymbolRate,
- mOuterFec, mAnnex, mSpectralInversion);
+ mOuterFec, mAnnex, mSpectralInversion, mInterleaveMode);
}
}
diff --git a/media/java/android/media/tv/tuner/frontend/DvbsFrontendSettings.java b/media/java/android/media/tv/tuner/frontend/DvbsFrontendSettings.java
index 60b070f..343dbb1 100644
--- a/media/java/android/media/tv/tuner/frontend/DvbsFrontendSettings.java
+++ b/media/java/android/media/tv/tuner/frontend/DvbsFrontendSettings.java
@@ -23,6 +23,8 @@
import android.annotation.SystemApi;
import android.hardware.tv.tuner.V1_0.Constants;
import android.media.tv.tuner.Tuner;
+import android.media.tv.tuner.TunerVersionChecker;
+
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
@@ -36,6 +38,44 @@
public class DvbsFrontendSettings extends FrontendSettings {
/** @hide */
@IntDef(flag = true,
+ prefix = "SCAN_TYPE_",
+ value = {SCAN_TYPE_UNDEFINED, SCAN_TYPE_DIRECT, SCAN_TYPE_DISEQC,
+ SCAN_TYPE_UNICABLE, SCAN_TYPE_JESS})
+ @Retention(RetentionPolicy.SOURCE)
+ public @interface ScanType {}
+
+ /**
+ * Dvbs scan type undefined.
+ */
+ public static final int SCAN_TYPE_UNDEFINED =
+ android.hardware.tv.tuner.V1_1.Constants.FrontendDvbsScanType.UNDEFINED;
+
+ /**
+ * Dvbs scan type DIRECT.
+ */
+ public static final int SCAN_TYPE_DIRECT =
+ android.hardware.tv.tuner.V1_1.Constants.FrontendDvbsScanType.DIRECT;
+
+ /**
+ * Dvbs scan type DISEQC.
+ */
+ public static final int SCAN_TYPE_DISEQC =
+ android.hardware.tv.tuner.V1_1.Constants.FrontendDvbsScanType.DISEQC;
+
+ /**
+ * Dvbs scan type UNICABLE.
+ */
+ public static final int SCAN_TYPE_UNICABLE =
+ android.hardware.tv.tuner.V1_1.Constants.FrontendDvbsScanType.UNICABLE;
+
+ /**
+ * Dvbs scan type JESS.
+ */
+ public static final int SCAN_TYPE_JESS =
+ android.hardware.tv.tuner.V1_1.Constants.FrontendDvbsScanType.JESS;
+
+ /** @hide */
+ @IntDef(flag = true,
prefix = "MODULATION_",
value = {MODULATION_UNDEFINED, MODULATION_AUTO, MODULATION_MOD_QPSK,
MODULATION_MOD_8PSK, MODULATION_MOD_16QAM, MODULATION_MOD_16PSK,
@@ -218,9 +258,12 @@
private final int mInputStreamId;
private final int mStandard;
private final int mVcmMode;
+ // Dvbs scan type is only supported in Tuner 1.1 or higher.
+ private final int mScanType;
private DvbsFrontendSettings(int frequency, int modulation, DvbsCodeRate codeRate,
- int symbolRate, int rolloff, int pilot, int inputStreamId, int standard, int vcm) {
+ int symbolRate, int rolloff, int pilot, int inputStreamId, int standard, int vcm,
+ int scanType) {
super(frequency);
mModulation = modulation;
mCodeRate = codeRate;
@@ -230,6 +273,7 @@
mInputStreamId = inputStreamId;
mStandard = standard;
mVcmMode = vcm;
+ mScanType = scanType;
}
/**
@@ -286,6 +330,13 @@
public int getVcmMode() {
return mVcmMode;
}
+ /**
+ * Get scan type.
+ */
+ @ScanType
+ public int getScanType() {
+ return mScanType;
+ }
/**
* Creates a builder for {@link DvbsFrontendSettings}.
@@ -308,6 +359,7 @@
private int mInputStreamId = Tuner.INVALID_STREAM_ID;
private int mStandard = STANDARD_AUTO;
private int mVcmMode = VCM_MODE_UNDEFINED;
+ private int mScanType = SCAN_TYPE_UNDEFINED;
private Builder() {
}
@@ -325,6 +377,24 @@
}
/**
+ * Set the scan type.
+ *
+ * <p>This API is only supported by Tuner HAL 1.1 or higher. Unsupported version would cause
+ * no-op. Use {@link TunerVersionChecker.getTunerVersion()} to check the version.
+ *
+ * @param scanType the value to set as the scan type. Default value is
+ * {@link android.media.tv.tuner.frontend.DvbsFrontendSettings#DVBS_SCAN_TYPE_UNDEFINED}.
+ */
+ @NonNull
+ public Builder setScanType(@ScanType int scanType) {
+ if (TunerVersionChecker.checkHigherOrEqualVersionTo(
+ TunerVersionChecker.TUNER_VERSION_1_1, "setScanType")) {
+ mScanType = scanType;
+ }
+ return this;
+ }
+
+ /**
* Sets Modulation.
*
* <p>Default value is {@link #MODULATION_UNDEFINED}.
@@ -411,7 +481,7 @@
@NonNull
public DvbsFrontendSettings build() {
return new DvbsFrontendSettings(mFrequency, mModulation, mCodeRate, mSymbolRate,
- mRolloff, mPilot, mInputStreamId, mStandard, mVcmMode);
+ mRolloff, mPilot, mInputStreamId, mStandard, mVcmMode, mScanType);
}
}
diff --git a/media/java/android/media/tv/tuner/frontend/DvbtFrontendSettings.java b/media/java/android/media/tv/tuner/frontend/DvbtFrontendSettings.java
index 5c057de..07d1797 100644
--- a/media/java/android/media/tv/tuner/frontend/DvbtFrontendSettings.java
+++ b/media/java/android/media/tv/tuner/frontend/DvbtFrontendSettings.java
@@ -21,6 +21,7 @@
import android.annotation.NonNull;
import android.annotation.SystemApi;
import android.hardware.tv.tuner.V1_0.Constants;
+import android.media.tv.tuner.TunerVersionChecker;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
@@ -75,8 +76,21 @@
* 32K Transmission Mode.
*/
public static final int TRANSMISSION_MODE_32K = Constants.FrontendDvbtTransmissionMode.MODE_32K;
-
-
+ /**
+ * 8K Transmission Extended Mode.
+ */
+ public static final int TRANSMISSION_MODE_EXTENDED_8K =
+ android.hardware.tv.tuner.V1_1.Constants.FrontendDvbtTransmissionMode.MODE_8K_E;
+ /**
+ * 16K Transmission Extended Mode.
+ */
+ public static final int TRANSMISSION_MODE_EXTENDED_16K =
+ android.hardware.tv.tuner.V1_1.Constants.FrontendDvbtTransmissionMode.MODE_16K_E;
+ /**
+ * 32K Transmission Extended Mode.
+ */
+ public static final int TRANSMISSION_MODE_EXTENDED_32K =
+ android.hardware.tv.tuner.V1_1.Constants.FrontendDvbtTransmissionMode.MODE_32K_E;
/** @hide */
@IntDef(flag = true,
@@ -124,8 +138,9 @@
@IntDef(flag = true,
prefix = "CONSTELLATION_",
value = {CONSTELLATION_UNDEFINED, CONSTELLATION_AUTO, CONSTELLATION_QPSK,
- CONSTELLATION_16QAM, CONSTELLATION_64QAM,
- CONSTELLATION_256QAM})
+ CONSTELLATION_16QAM, CONSTELLATION_64QAM, CONSTELLATION_256QAM,
+ CONSTELLATION_QPSK_R, CONSTELLATION_16QAM_R, CONSTELLATION_64QAM_R,
+ CONSTELLATION_256QAM_R})
@Retention(RetentionPolicy.SOURCE)
public @interface Constellation {}
@@ -157,7 +172,30 @@
*/
public static final int CONSTELLATION_256QAM =
Constants.FrontendDvbtConstellation.CONSTELLATION_256QAM;
-
+ /**
+ * QPSK Rotated Constellation.
+ */
+ public static final int CONSTELLATION_QPSK_R =
+ android.hardware.tv.tuner.V1_1.Constants.FrontendDvbtConstellation
+ .CONSTELLATION_QPSK_R;
+ /**
+ * 16QAM Rotated Constellation.
+ */
+ public static final int CONSTELLATION_16QAM_R =
+ android.hardware.tv.tuner.V1_1.Constants.FrontendDvbtConstellation
+ .CONSTELLATION_16QAM_R;
+ /**
+ * 64QAM Rotated Constellation.
+ */
+ public static final int CONSTELLATION_64QAM_R =
+ android.hardware.tv.tuner.V1_1.Constants.FrontendDvbtConstellation
+ .CONSTELLATION_64QAM_R;
+ /**
+ * 256QAM Rotated Constellation.
+ */
+ public static final int CONSTELLATION_256QAM_R =
+ android.hardware.tv.tuner.V1_1.Constants.FrontendDvbtConstellation
+ .CONSTELLATION_256QAM_R;
/** @hide */
@IntDef(flag = true,
@@ -366,8 +404,7 @@
*/
public static final int PLP_MODE_MANUAL = Constants.FrontendDvbtPlpMode.MANUAL;
-
- private final int mTransmissionMode;
+ private int mTransmissionMode;
private final int mBandwidth;
private final int mConstellation;
private final int mHierarchy;
@@ -489,6 +526,19 @@
return mPlpGroupId;
}
+ private static boolean isExtendedTransmissionMode(@TransmissionMode int transmissionMode) {
+ return transmissionMode == TRANSMISSION_MODE_EXTENDED_8K
+ || transmissionMode == TRANSMISSION_MODE_EXTENDED_16K
+ || transmissionMode == TRANSMISSION_MODE_EXTENDED_32K;
+ }
+
+ private static boolean isExtendedConstellation(@Constellation int constellation) {
+ return constellation == CONSTELLATION_QPSK_R
+ || constellation == CONSTELLATION_16QAM_R
+ || constellation == CONSTELLATION_64QAM_R
+ || constellation == CONSTELLATION_256QAM_R;
+ }
+
/**
* Creates a builder for {@link DvbtFrontendSettings}.
*/
@@ -534,13 +584,23 @@
/**
* Sets Transmission Mode.
*
+ * <p>{@link #TRANSMISSION_MODE_EXTENDED_8K}, {@link #TRANSMISSION_MODE_EXTENDED_16K} and
+ * {@link #TRANSMISSION_MODE_EXTENDED_32K} are only supported by Tuner HAL 1.1 or higher.
+ * Unsupported version would cause no-op. Use {@link TunerVersionChecker.getTunerVersion()}
+ * to check the version.
+ *
* <p>Default value is {@link #TRANSMISSION_MODE_UNDEFINED}.
*/
@NonNull
public Builder setTransmissionMode(@TransmissionMode int transmissionMode) {
- mTransmissionMode = transmissionMode;
+ if (!isExtendedTransmissionMode(transmissionMode)
+ || TunerVersionChecker.checkHigherOrEqualVersionTo(
+ TunerVersionChecker.TUNER_VERSION_1_1, "set TransmissionMode Ext")) {
+ mTransmissionMode = transmissionMode;
+ }
return this;
}
+
/**
* Sets Bandwidth.
*
@@ -554,11 +614,20 @@
/**
* Sets Constellation.
*
+ * <p>{@link #CONSTELLATION_QPSK_R}, {@link #CONSTELLATION_16QAM_R},
+ * {@link #CONSTELLATION_64QAM_R} and {@link #CONSTELLATION_256QAM_Rare} are only supported
+ * by Tuner HAL 1.1 or higher. Unsupported version would cause no-op. Use
+ * {@link TunerVersionChecker.getTunerVersion()} to check the version.
+ *
* <p>Default value is {@link #CONSTELLATION_UNDEFINED}.
*/
@NonNull
public Builder setConstellation(@Constellation int constellation) {
- mConstellation = constellation;
+ if (!isExtendedConstellation(constellation)
+ || TunerVersionChecker.checkHigherOrEqualVersionTo(
+ TunerVersionChecker.TUNER_VERSION_1_1, "set Constellation Ext")) {
+ mConstellation = constellation;
+ }
return this;
}
/**
diff --git a/media/java/android/media/tv/tuner/frontend/FrontendSettings.java b/media/java/android/media/tv/tuner/frontend/FrontendSettings.java
index 2f2fa97..82f7afa 100644
--- a/media/java/android/media/tv/tuner/frontend/FrontendSettings.java
+++ b/media/java/android/media/tv/tuner/frontend/FrontendSettings.java
@@ -17,9 +17,12 @@
package android.media.tv.tuner.frontend;
import android.annotation.IntDef;
+import android.annotation.IntRange;
import android.annotation.LongDef;
import android.annotation.SystemApi;
import android.hardware.tv.tuner.V1_0.Constants;
+import android.media.tv.tuner.Tuner;
+import android.media.tv.tuner.TunerVersionChecker;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
@@ -241,9 +244,36 @@
*/
public static final long FEC_77_90 = Constants.FrontendInnerFec.FEC_77_90;
+ /** @hide */
+ @IntDef(prefix = "FRONTEND_SPECTRAL_INVERSION_",
+ value = {FRONTEND_SPECTRAL_INVERSION_UNDEFINED, FRONTEND_SPECTRAL_INVERSION_NORMAL,
+ FRONTEND_SPECTRAL_INVERSION_INVERTED})
+ @Retention(RetentionPolicy.SOURCE)
+ public @interface FrontendSpectralInversion {}
+
+ /**
+ * Spectral Inversion Type undefined.
+ */
+ public static final int FRONTEND_SPECTRAL_INVERSION_UNDEFINED =
+ Constants.FrontendDvbcSpectralInversion.UNDEFINED;
+ /**
+ * Normal Spectral Inversion.
+ */
+ public static final int FRONTEND_SPECTRAL_INVERSION_NORMAL =
+ Constants.FrontendDvbcSpectralInversion.NORMAL;
+ /**
+ * Inverted Spectral Inversion.
+ */
+ public static final int FRONTEND_SPECTRAL_INVERSION_INVERTED =
+ Constants.FrontendDvbcSpectralInversion.INVERTED;
+
private final int mFrequency;
+ // End frequency is only supported in Tuner 1.1 or higher.
+ private int mEndFrequency = Tuner.INVALID_FRONTEND_SETTING_FREQUENCY;
+ // General spectral inversion is only supported in Tuner 1.1 or higher.
+ private int mSpectralInversion = FRONTEND_SPECTRAL_INVERSION_UNDEFINED;
FrontendSettings(int frequency) {
mFrequency = frequency;
@@ -263,4 +293,57 @@
public int getFrequency() {
return mFrequency;
}
+
+ /**
+ * Get the end frequency.
+ *
+ * @return the end frequency in Hz.
+ */
+ public int getEndFrequency() {
+ return mEndFrequency;
+ }
+
+ /**
+ * Get the spectral inversion.
+ *
+ * @return the value of the spectral inversion.
+ */
+ @FrontendSpectralInversion
+ public int getFrontendSpectralInversion() {
+ return mSpectralInversion;
+ }
+
+ /**
+ * Set Spectral Inversion.
+ *
+ * <p>This API is only supported by Tuner HAL 1.1 or higher. Unsupported version would cause
+ * no-op. Use {@link TunerVersionChecker.getTunerVersion()} to check the version.
+ *
+ * @param inversion the value to set as the spectral inversion. Default value is {@link
+ * #FRONTEND_SPECTRAL_INVERSION_UNDEFINED}.
+ */
+ public void setSpectralInversion(@FrontendSpectralInversion int inversion) {
+ if (TunerVersionChecker.checkHigherOrEqualVersionTo(
+ TunerVersionChecker.TUNER_VERSION_1_1, "setSpectralInversion")) {
+ mSpectralInversion = inversion;
+ }
+ }
+
+ /**
+ * Set End Frequency. This API is only supported with Tuner HAL 1.1 or higher. Otherwise it
+ * would be no-op.
+ *
+ * <p>This API is only supported by Tuner HAL 1.1 or higher. Unsupported version would cause
+ * no-op. Use {@link TunerVersionChecker.getTunerVersion()} to check the version.
+ *
+ * @param endFrequency the end frequency used during blind scan. The default value is
+ * {@link android.media.tv.tuner.Tuner#INVALID_FRONTEND_SETTING_FREQUENCY}.
+ */
+ @IntRange(from = 1)
+ public void setEndFrequency(int endFrequency) {
+ if (TunerVersionChecker.checkHigherOrEqualVersionTo(
+ TunerVersionChecker.TUNER_VERSION_1_1, "setEndFrequency")) {
+ mEndFrequency = endFrequency;
+ }
+ }
}
diff --git a/media/jni/android_media_Utils.cpp b/media/jni/android_media_Utils.cpp
index 2ef7b9e..b6c47fca 100644
--- a/media/jni/android_media_Utils.cpp
+++ b/media/jni/android_media_Utils.cpp
@@ -140,6 +140,27 @@
fmt = applyFormatOverrides(fmt, containerFormat);
switch (fmt) {
case HAL_PIXEL_FORMAT_YCbCr_420_888:
+ // Width and height should be multiple of 2. Wrong dataSize would be returned otherwise.
+ if (buffer->width % 2 != 0) {
+ ALOGE("YCbCr_420_888: width (%d) should be a multiple of 2", buffer->width);
+ return BAD_VALUE;
+ }
+
+ if (buffer->height % 2 != 0) {
+ ALOGE("YCbCr_420_888: height (%d) should be a multiple of 2", buffer->height);
+ return BAD_VALUE;
+ }
+
+ if (buffer->width <= 0) {
+ ALOGE("YCbCr_420_888: width (%d) should be a > 0", buffer->width);
+ return BAD_VALUE;
+ }
+
+ if (buffer->height <= 0) {
+ ALOGE("YCbCr_420_888: height (%d) should be a > 0", buffer->height);
+ return BAD_VALUE;
+ }
+
pData =
(idx == 0) ?
buffer->data :
@@ -160,6 +181,27 @@
break;
// NV21
case HAL_PIXEL_FORMAT_YCrCb_420_SP:
+ // Width and height should be multiple of 2. Wrong dataSize would be returned otherwise.
+ if (buffer->width % 2 != 0) {
+ ALOGE("YCrCb_420_SP: width (%d) should be a multiple of 2", buffer->width);
+ return BAD_VALUE;
+ }
+
+ if (buffer->height % 2 != 0) {
+ ALOGE("YCrCb_420_SP: height (%d) should be a multiple of 2", buffer->height);
+ return BAD_VALUE;
+ }
+
+ if (buffer->width <= 0) {
+ ALOGE("YCrCb_420_SP: width (%d) should be a > 0", buffer->width);
+ return BAD_VALUE;
+ }
+
+ if (buffer->height <= 0) {
+ ALOGE("YCrCb_420_SP: height (%d) should be a > 0", buffer->height);
+ return BAD_VALUE;
+ }
+
cr = buffer->data + (buffer->stride * buffer->height);
cb = cr + 1;
// only map until last pixel
@@ -178,6 +220,27 @@
rStride = buffer->width;
break;
case HAL_PIXEL_FORMAT_YV12:
+ // Width and height should be multiple of 2. Wrong dataSize would be returned otherwise.
+ if (buffer->width % 2 != 0) {
+ ALOGE("YV12: width (%d) should be a multiple of 2", buffer->width);
+ return BAD_VALUE;
+ }
+
+ if (buffer->height % 2 != 0) {
+ ALOGE("YV12: height (%d) should be a multiple of 2", buffer->height);
+ return BAD_VALUE;
+ }
+
+ if (buffer->width <= 0) {
+ ALOGE("YV12: width (%d) should be a > 0", buffer->width);
+ return BAD_VALUE;
+ }
+
+ if (buffer->height <= 0) {
+ ALOGE("YV12: height (%d) should be a > 0", buffer->height);
+ return BAD_VALUE;
+ }
+
// Y and C stride need to be 16 pixel aligned.
LOG_ALWAYS_FATAL_IF(buffer->stride % 16,
"Stride is not 16 pixel aligned %d", buffer->stride);
@@ -344,6 +407,11 @@
int flexFormat = format;
if (isPossiblyYUV(format)) {
res = buffer->lockAsyncYCbCr(inUsage, rect, &ycbcr, fenceFd);
+
+ if (res != OK) {
+ ALOGW("lockAsyncYCbCr failed with error %d", res);
+ }
+
pData = ycbcr.y;
flexFormat = HAL_PIXEL_FORMAT_YCbCr_420_888;
}
diff --git a/media/jni/android_media_tv_Tuner.cpp b/media/jni/android_media_tv_Tuner.cpp
index e0afe29..979dc06 100644
--- a/media/jni/android_media_tv_Tuner.cpp
+++ b/media/jni/android_media_tv_Tuner.cpp
@@ -134,6 +134,14 @@
using ::android::hardware::tv::tuner::V1_0::RecordSettings;
using ::android::hardware::tv::tuner::V1_1::Constant;
using ::android::hardware::tv::tuner::V1_1::Constant64Bit;
+using ::android::hardware::tv::tuner::V1_1::FrontendAnalogAftFlag;
+using ::android::hardware::tv::tuner::V1_1::FrontendAnalogSettingsExt1_1;
+using ::android::hardware::tv::tuner::V1_1::FrontendCableTimeInterleaveMode;
+using ::android::hardware::tv::tuner::V1_1::FrontendDvbsScanType;
+using ::android::hardware::tv::tuner::V1_1::FrontendDvbcSettingsExt1_1;
+using ::android::hardware::tv::tuner::V1_1::FrontendDvbsSettingsExt1_1;
+using ::android::hardware::tv::tuner::V1_1::FrontendDvbtSettingsExt1_1;
+using ::android::hardware::tv::tuner::V1_1::FrontendSpectralInversion;
struct fields_t {
jfieldID tunerContext;
@@ -309,9 +317,9 @@
/////////////// MediaEvent ///////////////////////
-MediaEvent::MediaEvent(sp<IFilter> iFilter, hidl_handle avHandle,
- uint64_t dataId, uint64_t dataLength, jobject obj) : mIFilter(iFilter),
- mDataId(dataId), mDataLength(dataLength), mBuffer(nullptr),
+MediaEvent::MediaEvent(sp<Filter> filter, hidl_handle avHandle,
+ uint64_t dataId, uint64_t dataSize, jobject obj) : mFilter(filter),
+ mDataId(dataId), mDataSize(dataSize), mBuffer(nullptr),
mDataIdRefCnt(0), mAvHandleRefCnt(0), mIonHandle(nullptr) {
JNIEnv *env = AndroidRuntime::getJNIEnv();
mMediaEventObj = env->NewWeakGlobalRef(obj);
@@ -335,7 +343,8 @@
void MediaEvent::finalize() {
if (mAvHandleRefCnt == 0) {
- mIFilter->releaseAvHandle(hidl_handle(mAvHandle), mDataIdRefCnt == 0 ? mDataId : 0);
+ mFilter->mFilterSp->releaseAvHandle(
+ hidl_handle(mAvHandle), mDataIdRefCnt == 0 ? mDataId : 0);
native_handle_close(mAvHandle);
}
}
@@ -348,7 +357,47 @@
if (mLinearBlockObj != NULL) {
return mLinearBlockObj;
}
- mIonHandle = new C2HandleIon(dup(mAvHandle->data[0]), mDataLength);
+
+ int fd;
+ int numInts = 0;
+ int memIndex;
+ int dataSize;
+ if (mAvHandle->numFds == 0) {
+ if (mFilter->mAvSharedHandle == NULL) {
+ ALOGE("Shared AV memory handle is not initialized.");
+ return NULL;
+ }
+ if (mFilter->mAvSharedHandle->numFds == 0) {
+ ALOGE("Shared AV memory handle is empty.");
+ return NULL;
+ }
+ fd = mFilter->mAvSharedHandle->data[0];
+ dataSize = mFilter->mAvSharedMemSize;
+ numInts = mFilter->mAvSharedHandle->numInts;
+ if (numInts > 0) {
+ // If the first int in the shared native handle has value, use it as the index
+ memIndex = mFilter->mAvSharedHandle->data[mFilter->mAvSharedHandle->numFds];
+ }
+ } else {
+ fd = mAvHandle->data[0];
+ dataSize = mDataSize;
+ numInts = mAvHandle->numInts;
+ if (numInts > 0) {
+ // Otherwise if the first int in the av native handle returned from the filter
+ // event has value, use it as the index
+ memIndex = mAvHandle->data[mAvHandle->numFds];
+ } else {
+ if (mFilter->mAvSharedHandle != NULL) {
+ numInts = mFilter->mAvSharedHandle->numInts;
+ if (numInts > 0) {
+ // If the first int in the shared native handle has value, use it as the index
+ memIndex = mFilter->mAvSharedHandle->data[mFilter->mAvSharedHandle->numFds];
+ }
+ }
+ }
+ }
+
+ mIonHandle = new C2HandleIon(dup(fd), dataSize);
std::shared_ptr<C2LinearBlock> block = _C2BlockFactory::CreateLinearBlock(mIonHandle);
if (block != nullptr) {
// CreateLinearBlock delete mIonHandle after it create block successfully.
@@ -357,13 +406,11 @@
JNIEnv *env = AndroidRuntime::getJNIEnv();
std::unique_ptr<JMediaCodecLinearBlock> context{new JMediaCodecLinearBlock};
context->mBlock = block;
- std::shared_ptr<C2Buffer> pC2Buffer = context->toC2Buffer(0, mDataLength);
+ std::shared_ptr<C2Buffer> pC2Buffer = context->toC2Buffer(0, dataSize);
context->mBuffer = pC2Buffer;
mC2Buffer = pC2Buffer;
- if (mAvHandle->numInts > 0) {
- // use first int in the native_handle as the index
- int index = mAvHandle->data[mAvHandle->numFds];
- std::shared_ptr<C2Param> c2param = std::make_shared<C2DataIdInfo>(index, mDataId);
+ if (numInts > 0) {
+ std::shared_ptr<C2Param> c2param = std::make_shared<C2DataIdInfo>(memIndex, mDataId);
std::shared_ptr<C2Info> info(std::static_pointer_cast<C2Info>(c2param));
pC2Buffer->setInfo(info);
}
@@ -470,7 +517,7 @@
if (mediaEvent.avMemory.getNativeHandle() != NULL || mediaEvent.avDataId != 0) {
sp<MediaEvent> mediaEventSp =
- new MediaEvent(mIFilter, mediaEvent.avMemory,
+ new MediaEvent(mFilter, mediaEvent.avMemory,
mediaEvent.avDataId, dataLength + offset, obj);
mediaEventSp->mAvHandleRefCnt++;
env->SetLongField(obj, eventContext, (jlong) mediaEventSp.get());
@@ -690,7 +737,7 @@
}
}
env->CallVoidMethod(
- mFilter,
+ mFilter->mFilterObj,
gFields.onFilterEventID,
array);
return Void();
@@ -709,7 +756,7 @@
ALOGD("FilterCallback::onFilterStatus");
JNIEnv *env = AndroidRuntime::getJNIEnv();
env->CallVoidMethod(
- mFilter,
+ mFilter->mFilterObj,
gFields.onFilterStatusID,
(jint)status);
return Void();
@@ -717,17 +764,11 @@
void FilterCallback::setFilter(const sp<Filter> filter) {
ALOGD("FilterCallback::setFilter");
- mFilter = filter->mFilterObj;
- mIFilter = filter->mFilterSp;
+ // JNI Object
+ mFilter = filter;
}
-FilterCallback::~FilterCallback() {
- JNIEnv *env = AndroidRuntime::getJNIEnv();
- if (mFilter != NULL) {
- env->DeleteWeakGlobalRef(mFilter);
- mFilter = NULL;
- }
-}
+FilterCallback::~FilterCallback() {}
/////////////// Filter ///////////////////////
@@ -1034,6 +1075,7 @@
return NULL;
}
mFe = fe;
+ mFe_1_1 = ::android::hardware::tv::tuner::V1_1::IFrontend::castFrom(mFe);
mFeId = id;
if (mDemux != NULL) {
mDemux->setFrontendDataSource(mFeId);
@@ -1343,12 +1385,21 @@
return lnbObj;
}
-int JTuner::tune(const FrontendSettings& settings) {
+int JTuner::tune(const FrontendSettings& settings, const FrontendSettingsExt1_1& settingsExt1_1) {
if (mFe == NULL) {
ALOGE("frontend is not initialized");
return (int)Result::INVALID_STATE;
}
- Result result = mFe->tune(settings);
+ Result result;
+ sp<::android::hardware::tv::tuner::V1_1::IFrontend> fe_1_1 =
+ ::android::hardware::tv::tuner::V1_1::IFrontend::castFrom(mFe);
+ if (fe_1_1 == NULL) {
+ ALOGD("1.1 frontend is not found. Using 1.0 instead.");
+ result = mFe->tune(settings);
+ return (int)result;
+ }
+
+ result = fe_1_1->tune_1_1(settings, settingsExt1_1);
return (int)result;
}
@@ -1361,12 +1412,22 @@
return (int)result;
}
-int JTuner::scan(const FrontendSettings& settings, FrontendScanType scanType) {
+int JTuner::scan(const FrontendSettings& settings, FrontendScanType scanType,
+ const FrontendSettingsExt1_1& settingsExt1_1) {
if (mFe == NULL) {
ALOGE("frontend is not initialized");
return (int)Result::INVALID_STATE;
}
- Result result = mFe->scan(settings, scanType);
+ Result result;
+ sp<::android::hardware::tv::tuner::V1_1::IFrontend> fe_1_1 =
+ ::android::hardware::tv::tuner::V1_1::IFrontend::castFrom(mFe);
+ if (fe_1_1 == NULL) {
+ ALOGD("1.1 frontend is not found. Using 1.0 instead.");
+ result = mFe->scan(settings, scanType);
+ return (int)result;
+ }
+
+ result = fe_1_1->scan_1_1(settings, scanType, settingsExt1_1);
return (int)result;
}
@@ -1493,6 +1554,27 @@
return (int) r;
}
+int JTuner::linkCiCam(int id) {
+ if (mFe_1_1 == NULL) {
+ ALOGE("frontend 1.1 is not initialized");
+ return (int)Constant::INVALID_LTS_ID;
+ }
+
+ Result res;
+ uint32_t ltsId;
+ mFe_1_1->linkCiCam(static_cast<uint32_t>(id),
+ [&](Result r, uint32_t id) {
+ res = r;
+ ltsId = id;
+ });
+
+ if (res != Result::SUCCESS) {
+ return (int)Constant::INVALID_LTS_ID;
+ }
+
+ return (int) ltsId;
+}
+
int JTuner::disconnectCiCam() {
if (mDemux == NULL) {
Result r = openDemux();
@@ -1504,6 +1586,18 @@
return (int) r;
}
+
+int JTuner::unlinkCiCam(int id) {
+ if (mFe_1_1 == NULL) {
+ ALOGE("frontend 1.1 is not initialized");
+ return (int)Result::INVALID_STATE;
+ }
+
+ Result r = mFe_1_1->unlinkCiCam(static_cast<uint32_t>(id));
+
+ return (int) r;
+}
+
jobject JTuner::openDescrambler() {
ALOGD("JTuner::openDescrambler");
if (mTuner == nullptr || mDemux == nullptr) {
@@ -1575,9 +1669,33 @@
sp<Filter> filterSp = new Filter(iFilterSp, filterObj);
filterSp->incStrong(filterObj);
env->SetLongField(filterObj, gFields.filterContext, (jlong)filterSp.get());
-
+ filterSp->mIsMediaFilter = false;
+ filterSp->mAvSharedHandle = NULL;
callback->setFilter(filterSp);
+ if (type.mainType == DemuxFilterMainType::MMTP) {
+ if (type.subType.mmtpFilterType() == DemuxMmtpFilterType::AUDIO ||
+ type.subType.mmtpFilterType() == DemuxMmtpFilterType::VIDEO) {
+ filterSp->mIsMediaFilter = true;
+ }
+ }
+
+ if (type.mainType == DemuxFilterMainType::TS) {
+ if (type.subType.tsFilterType() == DemuxTsFilterType::AUDIO ||
+ type.subType.tsFilterType() == DemuxTsFilterType::VIDEO) {
+ filterSp->mIsMediaFilter = true;
+ }
+ }
+
+ if (iFilterSp_1_1 != NULL && filterSp->mIsMediaFilter) {
+ iFilterSp_1_1->getAvSharedHandle([&](Result r, hidl_handle avMemory, uint64_t avMemSize) {
+ if (r == Result::SUCCESS) {
+ filterSp->mAvSharedHandle = native_handle_clone(avMemory.getNativeHandle());
+ filterSp->mAvSharedMemSize = avMemSize;
+ }
+ });
+ }
+
return filterObj;
}
@@ -1947,6 +2065,10 @@
if (mFe != NULL) {
r = mFe->close();
}
+ if (r == Result::SUCCESS) {
+ mFe = NULL;
+ mFe_1_1 = NULL;
+ }
return (jint) r;
}
@@ -1955,6 +2077,9 @@
if (mDemux != NULL) {
r = mDemux->close();
}
+ if (r == Result::SUCCESS) {
+ mDemux = NULL;
+ }
return (jint) r;
}
@@ -2007,6 +2132,22 @@
return freq;
}
+static uint32_t getFrontendSettingsEndFreq(JNIEnv *env, const jobject& settings) {
+ jclass clazz = env->FindClass("android/media/tv/tuner/frontend/FrontendSettings");
+ jfieldID endFreqField = env->GetFieldID(clazz, "mEndFrequency", "I");
+ uint32_t endFreq = static_cast<uint32_t>(env->GetIntField(settings, endFreqField));
+ return endFreq;
+}
+
+static FrontendSpectralInversion getFrontendSettingsSpectralInversion(
+ JNIEnv *env, const jobject& settings) {
+ jclass clazz = env->FindClass("android/media/tv/tuner/frontend/FrontendSettings");
+ jfieldID inversionField = env->GetFieldID(clazz, "mSpectralInversion", "I");
+ FrontendSpectralInversion inversion =
+ static_cast<FrontendSpectralInversion>(env->GetIntField(settings, inversionField));
+ return inversion;
+}
+
static FrontendSettings getAnalogFrontendSettings(JNIEnv *env, const jobject& settings) {
FrontendSettings frontendSettings;
uint32_t freq = getFrontendSettingsFreq(env, settings);
@@ -2026,6 +2167,18 @@
return frontendSettings;
}
+static void getAnalogFrontendSettingsExt1_1(JNIEnv *env, const jobject& settings,
+ FrontendSettingsExt1_1& settingsExt1_1) {
+ jclass clazz = env->FindClass("android/media/tv/tuner/frontend/AnalogFrontendSettings");
+ FrontendAnalogAftFlag aftFlag =
+ static_cast<FrontendAnalogAftFlag>(
+ env->GetIntField(settings, env->GetFieldID(clazz, "mAftFlag", "I")));
+ FrontendAnalogSettingsExt1_1 analogExt1_1 {
+ .aftFlag = aftFlag,
+ };
+ settingsExt1_1.settingExt.analog(analogExt1_1);
+}
+
static hidl_vec<FrontendAtsc3PlpSettings> getAtsc3PlpSettings(
JNIEnv *env, const jobject& settings) {
jclass clazz = env->FindClass("android/media/tv/tuner/frontend/Atsc3FrontendSettings");
@@ -2145,6 +2298,19 @@
return frontendSettings;
}
+static void getDvbcFrontendSettingsExt1_1(JNIEnv *env, const jobject& settings,
+ FrontendSettingsExt1_1& settingsExt1_1) {
+ jclass clazz = env->FindClass("android/media/tv/tuner/frontend/DvbcFrontendSettings");
+ FrontendCableTimeInterleaveMode interleaveMode =
+ static_cast<FrontendCableTimeInterleaveMode>(
+ env->GetIntField(settings, env->GetFieldID(clazz, "mInterleaveMode", "I")));
+
+ FrontendDvbcSettingsExt1_1 dvbcExt1_1 {
+ .interleaveMode = interleaveMode,
+ };
+ settingsExt1_1.settingExt.dvbc(dvbcExt1_1);
+}
+
static FrontendDvbsCodeRate getDvbsCodeRate(JNIEnv *env, const jobject& settings) {
jclass clazz = env->FindClass("android/media/tv/tuner/frontend/DvbsFrontendSettings");
jobject jcodeRate =
@@ -2186,7 +2352,6 @@
uint32_t freq = getFrontendSettingsFreq(env, settings);
jclass clazz = env->FindClass("android/media/tv/tuner/frontend/DvbsFrontendSettings");
-
FrontendDvbsModulation modulation =
static_cast<FrontendDvbsModulation>(
env->GetIntField(settings, env->GetFieldID(clazz, "mModulation", "I")));
@@ -2225,6 +2390,22 @@
return frontendSettings;
}
+static void getDvbsFrontendSettingsExt1_1(JNIEnv *env, const jobject& settings,
+ FrontendSettingsExt1_1& settingsExt1_1) {
+ jclass clazz = env->FindClass("android/media/tv/tuner/frontend/DvbsFrontendSettings");
+ FrontendDvbsScanType scanType =
+ static_cast<FrontendDvbsScanType>(
+ env->GetIntField(settings, env->GetFieldID(clazz, "mScanType", "I")));
+ bool isDiseqcRxMessage = static_cast<bool>(env->GetBooleanField(
+ settings, env->GetFieldID(clazz, "mIsDiseqcRxMessage", "B")));
+
+ FrontendDvbsSettingsExt1_1 dvbsExt1_1 {
+ .scanType = scanType,
+ .isDiseqcRxMessage = isDiseqcRxMessage,
+ };
+ settingsExt1_1.settingExt.dvbs(dvbsExt1_1);
+}
+
static FrontendSettings getDvbtFrontendSettings(JNIEnv *env, const jobject& settings) {
FrontendSettings frontendSettings;
uint32_t freq = getFrontendSettingsFreq(env, settings);
@@ -2291,6 +2472,25 @@
return frontendSettings;
}
+static void getDvbtFrontendSettingsExt1_1(JNIEnv *env, const jobject& settings,
+ FrontendSettingsExt1_1& settingsExt1_1) {
+ jclass clazz = env->FindClass("android/media/tv/tuner/frontend/DvbtFrontendSettings");
+
+ FrontendDvbtSettingsExt1_1 dvbtExt1_1;
+ int transmissionMode =
+ env->GetIntField(settings, env->GetFieldID(clazz, "mTransmissionMode", "I"));
+ dvbtExt1_1.transmissionMode = static_cast<
+ ::android::hardware::tv::tuner::V1_1::FrontendDvbtTransmissionMode>(
+ transmissionMode);
+
+ int constellation =
+ env->GetIntField(settings, env->GetFieldID(clazz, "mConstellation", "I"));
+ dvbtExt1_1.constellation = static_cast<
+ ::android::hardware::tv::tuner::V1_1::FrontendDvbtConstellation>(constellation);
+
+ settingsExt1_1.settingExt.dvbt(dvbtExt1_1);
+}
+
static FrontendSettings getIsdbsFrontendSettings(JNIEnv *env, const jobject& settings) {
FrontendSettings frontendSettings;
uint32_t freq = getFrontendSettingsFreq(env, settings);
@@ -2431,6 +2631,54 @@
}
}
+static FrontendSettingsExt1_1 getFrontendSettingsExt1_1(JNIEnv *env, int type, jobject settings) {
+ ALOGD("getFrontendSettingsExt1_1 %d", type);
+
+ FrontendSettingsExt1_1 settingsExt1_1 {
+ .endFrequency = static_cast<uint32_t>(Constant::INVALID_FRONTEND_SETTING_FREQUENCY),
+ .inversion = FrontendSpectralInversion::UNDEFINED,
+ };
+ settingsExt1_1.settingExt.noinit();
+ FrontendType feType = static_cast<FrontendType>(type);
+ switch(feType) {
+ case FrontendType::DVBS:
+ getDvbsFrontendSettingsExt1_1(env, settings, settingsExt1_1);
+ break;
+ case FrontendType::DVBT:
+ getDvbtFrontendSettingsExt1_1(env, settings, settingsExt1_1);
+ break;
+ case FrontendType::ANALOG:
+ getAnalogFrontendSettingsExt1_1(env, settings, settingsExt1_1);
+ break;
+ case FrontendType::ATSC3:
+ break;
+ case FrontendType::ATSC:
+ break;
+ case FrontendType::DVBC:
+ getDvbcFrontendSettingsExt1_1(env, settings, settingsExt1_1);
+ break;
+ case FrontendType::ISDBS:
+ break;
+ case FrontendType::ISDBS3:
+ break;
+ case FrontendType::ISDBT:
+ break;
+ default:
+ // should never happen because a type is associated with a subclass of
+ // FrontendSettings and not set by users
+ jniThrowExceptionFmt(env, "java/lang/IllegalArgumentException",
+ "Unsupported frontend type %d", type);
+ return FrontendSettingsExt1_1();
+ }
+
+ uint32_t endFreq = getFrontendSettingsEndFreq(env, settings);
+ FrontendSpectralInversion inversion = getFrontendSettingsSpectralInversion(env, settings);
+ settingsExt1_1.endFrequency = endFreq;
+ settingsExt1_1.inversion = inversion;
+
+ return settingsExt1_1;
+}
+
static sp<Filter> getFilter(JNIEnv *env, jobject filter) {
return (Filter *)env->GetLongField(filter, gFields.filterContext);
}
@@ -2572,7 +2820,9 @@
static int android_media_tv_Tuner_tune(JNIEnv *env, jobject thiz, jint type, jobject settings) {
sp<JTuner> tuner = getTuner(env, thiz);
- return tuner->tune(getFrontendSettings(env, type, settings));
+ FrontendSettings setting = getFrontendSettings(env, type, settings);
+ FrontendSettingsExt1_1 settingExt = getFrontendSettingsExt1_1(env, type, settings);
+ return tuner->tune(setting, settingExt);
}
static int android_media_tv_Tuner_stop_tune(JNIEnv *env, jobject thiz) {
@@ -2583,8 +2833,9 @@
static int android_media_tv_Tuner_scan(
JNIEnv *env, jobject thiz, jint settingsType, jobject settings, jint scanType) {
sp<JTuner> tuner = getTuner(env, thiz);
- return tuner->scan(getFrontendSettings(
- env, settingsType, settings), static_cast<FrontendScanType>(scanType));
+ FrontendSettings setting = getFrontendSettings(env, settingsType, settings);
+ FrontendSettingsExt1_1 settingExt = getFrontendSettingsExt1_1(env, settingsType, settings);
+ return tuner->scan(setting, static_cast<FrontendScanType>(scanType), settingExt);
}
static int android_media_tv_Tuner_stop_scan(JNIEnv *env, jobject thiz) {
@@ -2629,11 +2880,21 @@
return tuner->connectCiCam(id);
}
+static int android_media_tv_Tuner_link_cicam(JNIEnv *env, jobject thiz, jint id) {
+ sp<JTuner> tuner = getTuner(env, thiz);
+ return tuner->linkCiCam(id);
+}
+
static int android_media_tv_Tuner_disconnect_cicam(JNIEnv *env, jobject thiz) {
sp<JTuner> tuner = getTuner(env, thiz);
return tuner->disconnectCiCam();
}
+static int android_media_tv_Tuner_unlink_cicam(JNIEnv *env, jobject thiz, jint id) {
+ sp<JTuner> tuner = getTuner(env, thiz);
+ return tuner->unlinkCiCam(id);
+}
+
static jobject android_media_tv_Tuner_get_frontend_info(JNIEnv *env, jobject thiz, jint id) {
sp<JTuner> tuner = getTuner(env, thiz);
return tuner->getFrontendInfo(id);
@@ -3041,6 +3302,29 @@
return filterSettings;
}
+static Result configureIpFilterContextId(
+ JNIEnv *env, sp<IFilter> iFilterSp, jobject ipFilterConfigObj) {
+ jclass clazz = env->FindClass(
+ "android/media/tv/tuner/filter/IpFilterConfiguration");
+ uint32_t cid = env->GetIntField(ipFilterConfigObj, env->GetFieldID(
+ clazz, "mIpFilterContextId", "I"));
+ Result res = Result::SUCCESS;
+ if (cid != static_cast<uint32_t>(Constant::INVALID_IP_FILTER_CONTEXT_ID)) {
+ sp<::android::hardware::tv::tuner::V1_1::IFilter> iFilterSp_1_1;
+ iFilterSp_1_1 = ::android::hardware::tv::tuner::V1_1::IFilter::castFrom(iFilterSp);
+
+ if (iFilterSp_1_1 != NULL) {
+ res = iFilterSp_1_1->configureIpCid(cid);
+ if (res != Result::SUCCESS) {
+ return res;
+ }
+ } else {
+ ALOGW("configureIpCid is not supported with the current HAL implementation.");
+ }
+ }
+ return res;
+}
+
static jint copyData(JNIEnv *env, std::unique_ptr<MQ>& mq, EventFlag* flag, jbyteArray buffer,
jlong offset, jlong size) {
ALOGD("copyData, size=%ld, offset=%ld", (long) size, (long) offset);
@@ -3084,6 +3368,13 @@
return (jint) res;
}
+ if (static_cast<DemuxFilterMainType>(type) == DemuxFilterMainType::IP) {
+ res = configureIpFilterContextId(env, iFilterSp, settings);
+ if (res != Result::SUCCESS) {
+ return (jint) res;
+ }
+ }
+
MQDescriptorSync<uint8_t> filterMQDesc;
Result getQueueDescResult = Result::UNKNOWN_ERROR;
if (filterSp->mFilterMQ == NULL) {
@@ -3786,6 +4077,10 @@
{ "nativeGetAvSyncTime", "(I)Ljava/lang/Long;",
(void *)android_media_tv_Tuner_get_av_sync_time },
{ "nativeConnectCiCam", "(I)I", (void *)android_media_tv_Tuner_connect_cicam },
+ { "nativeLinkCiCam", "(I)I",
+ (void *)android_media_tv_Tuner_link_cicam },
+ { "nativeUnlinkCiCam", "(I)I",
+ (void *)android_media_tv_Tuner_unlink_cicam },
{ "nativeDisconnectCiCam", "()I", (void *)android_media_tv_Tuner_disconnect_cicam },
{ "nativeGetFrontendInfo", "(I)Landroid/media/tv/tuner/frontend/FrontendInfo;",
(void *)android_media_tv_Tuner_get_frontend_info },
diff --git a/media/jni/android_media_tv_Tuner.h b/media/jni/android_media_tv_Tuner.h
index d7dc600..d70a5ff 100644
--- a/media/jni/android_media_tv_Tuner.h
+++ b/media/jni/android_media_tv_Tuner.h
@@ -19,6 +19,7 @@
#include <android/hardware/tv/tuner/1.1/IFilter.h>
#include <android/hardware/tv/tuner/1.1/IFilterCallback.h>
+#include <android/hardware/tv/tuner/1.1/IFrontend.h>
#include <android/hardware/tv/tuner/1.1/ITuner.h>
#include <android/hardware/tv/tuner/1.1/types.h>
@@ -54,6 +55,7 @@
using ::android::hardware::tv::tuner::V1_0::FrontendScanMessageType;
using ::android::hardware::tv::tuner::V1_0::FrontendScanType;
using ::android::hardware::tv::tuner::V1_0::FrontendSettings;
+using ::android::hardware::tv::tuner::V1_1::FrontendSettingsExt1_1;
using ::android::hardware::tv::tuner::V1_0::IDemux;
using ::android::hardware::tv::tuner::V1_0::IDescrambler;
using ::android::hardware::tv::tuner::V1_0::IDvr;
@@ -117,28 +119,6 @@
int mFd;
};
-struct MediaEvent : public RefBase {
- MediaEvent(sp<IFilter> iFilter, hidl_handle avHandle, uint64_t dataId,
- uint64_t dataLength, jobject obj);
- ~MediaEvent();
- jobject getLinearBlock();
- uint64_t getAudioHandle();
- void finalize();
-
- sp<IFilter> mIFilter;
- native_handle_t* mAvHandle;
- uint64_t mDataId;
- uint64_t mDataLength;
- uint8_t* mBuffer;
- android::Mutex mLock;
- int mDataIdRefCnt;
- int mAvHandleRefCnt;
- jweak mMediaEventObj;
- jweak mLinearBlockObj;
- C2HandleIon* mIonHandle;
- std::weak_ptr<C2Buffer> mC2Buffer;
-};
-
struct Filter : public RefBase {
Filter(sp<IFilter> sp, jobject obj);
~Filter();
@@ -148,6 +128,31 @@
std::unique_ptr<MQ> mFilterMQ;
EventFlag* mFilterMQEventFlag;
jweak mFilterObj;
+ native_handle_t* mAvSharedHandle;
+ uint64_t mAvSharedMemSize;
+ bool mIsMediaFilter;
+};
+
+struct MediaEvent : public RefBase {
+ MediaEvent(sp<Filter> filter, hidl_handle avHandle, uint64_t dataId,
+ uint64_t dataSize, jobject obj);
+ ~MediaEvent();
+ jobject getLinearBlock();
+ uint64_t getAudioHandle();
+ void finalize();
+
+ sp<Filter> mFilter;
+ native_handle_t* mAvHandle;
+ uint64_t mDataId;
+ uint64_t mDataSize;
+ uint8_t* mBuffer;
+ android::Mutex mLock;
+ int mDataIdRefCnt;
+ int mAvHandleRefCnt;
+ jweak mMediaEventObj;
+ jweak mLinearBlockObj;
+ C2HandleIon* mIonHandle;
+ std::weak_ptr<C2Buffer> mC2Buffer;
};
struct FilterCallback : public IFilterCallback {
@@ -159,8 +164,7 @@
void setFilter(const sp<Filter> filter);
private:
- jweak mFilter;
- sp<IFilter> mIFilter;
+ sp<Filter> mFilter;
jobjectArray getSectionEvent(
jobjectArray& arr, const std::vector<DemuxFilterEvent::Event>& events);
jobjectArray getMediaEvent(
@@ -207,14 +211,17 @@
jobject getAvSyncHwId(sp<Filter> filter);
jobject getAvSyncTime(jint id);
int connectCiCam(jint id);
+ int linkCiCam(jint id);
int disconnectCiCam();
+ int unlinkCiCam(jint id);
jobject getFrontendIds();
jobject openFrontendById(int id);
jint closeFrontendById(int id);
jobject getFrontendInfo(int id);
- int tune(const FrontendSettings& settings);
+ int tune(const FrontendSettings& settings, const FrontendSettingsExt1_1& settingsExt1_1);
int stopTune();
- int scan(const FrontendSettings& settings, FrontendScanType scanType);
+ int scan(const FrontendSettings& settings, FrontendScanType scanType,
+ const FrontendSettingsExt1_1& settingsExt1_1);
int stopScan();
int setLnb(int id);
int setLna(bool enable);
@@ -245,6 +252,7 @@
static int mTunerVersion;
hidl_vec<FrontendId> mFeIds;
sp<IFrontend> mFe;
+ sp<::android::hardware::tv::tuner::V1_1::IFrontend> mFe_1_1;
int mFeId;
hidl_vec<LnbId> mLnbIds;
sp<ILnb> mLnb;
diff --git a/native/graphics/jni/imagedecoder.cpp b/native/graphics/jni/imagedecoder.cpp
index 23035b6..ac4c16a 100644
--- a/native/graphics/jni/imagedecoder.cpp
+++ b/native/graphics/jni/imagedecoder.cpp
@@ -353,3 +353,18 @@
ImageDecoder* imageDecoder = toDecoder(decoder);
return imageDecoder->mCodec->codec()->getFrameCount() > 1;
}
+
+int32_t AImageDecoder_getRepeatCount(AImageDecoder* decoder) {
+ if (!decoder) return ANDROID_IMAGE_DECODER_BAD_PARAMETER;
+
+ ImageDecoder* imageDecoder = toDecoder(decoder);
+ const int count = imageDecoder->mCodec->codec()->getRepetitionCount();
+
+ // Skia should not report anything out of range, but defensively treat
+ // negative and too big as INFINITE.
+ if (count == SkCodec::kRepetitionCountInfinite || count < 0
+ || count > std::numeric_limits<int32_t>::max()) {
+ return ANDROID_IMAGE_DECODER_INFINITE;
+ }
+ return count;
+}
diff --git a/native/graphics/jni/libjnigraphics.map.txt b/native/graphics/jni/libjnigraphics.map.txt
index af2c455..a184ab9 100644
--- a/native/graphics/jni/libjnigraphics.map.txt
+++ b/native/graphics/jni/libjnigraphics.map.txt
@@ -14,6 +14,7 @@
AImageDecoder_computeSampledSize; # introduced=30
AImageDecoder_setCrop; # introduced=30
AImageDecoder_isAnimated; # introduced=31
+ AImageDecoder_getRepeatCount; # introduced=31
AImageDecoderHeaderInfo_getWidth; # introduced=30
AImageDecoderHeaderInfo_getHeight; # introduced=30
AImageDecoderHeaderInfo_getMimeType; # introduced=30
diff --git a/non-updatable-api/current.txt b/non-updatable-api/current.txt
index 8596f87..e3718c9 100644
--- a/non-updatable-api/current.txt
+++ b/non-updatable-api/current.txt
@@ -2889,6 +2889,7 @@
field public static final int GESTURE_2_FINGER_DOUBLE_TAP = 20; // 0x14
field public static final int GESTURE_2_FINGER_DOUBLE_TAP_AND_HOLD = 40; // 0x28
field public static final int GESTURE_2_FINGER_SINGLE_TAP = 19; // 0x13
+ field public static final int GESTURE_2_FINGER_SINGLE_TAP_AND_HOLD = 43; // 0x2b
field public static final int GESTURE_2_FINGER_SWIPE_DOWN = 26; // 0x1a
field public static final int GESTURE_2_FINGER_SWIPE_LEFT = 27; // 0x1b
field public static final int GESTURE_2_FINGER_SWIPE_RIGHT = 28; // 0x1c
@@ -2897,11 +2898,13 @@
field public static final int GESTURE_3_FINGER_DOUBLE_TAP = 23; // 0x17
field public static final int GESTURE_3_FINGER_DOUBLE_TAP_AND_HOLD = 41; // 0x29
field public static final int GESTURE_3_FINGER_SINGLE_TAP = 22; // 0x16
+ field public static final int GESTURE_3_FINGER_SINGLE_TAP_AND_HOLD = 44; // 0x2c
field public static final int GESTURE_3_FINGER_SWIPE_DOWN = 30; // 0x1e
field public static final int GESTURE_3_FINGER_SWIPE_LEFT = 31; // 0x1f
field public static final int GESTURE_3_FINGER_SWIPE_RIGHT = 32; // 0x20
field public static final int GESTURE_3_FINGER_SWIPE_UP = 29; // 0x1d
field public static final int GESTURE_3_FINGER_TRIPLE_TAP = 24; // 0x18
+ field public static final int GESTURE_3_FINGER_TRIPLE_TAP_AND_HOLD = 45; // 0x2d
field public static final int GESTURE_4_FINGER_DOUBLE_TAP = 38; // 0x26
field public static final int GESTURE_4_FINGER_DOUBLE_TAP_AND_HOLD = 42; // 0x2a
field public static final int GESTURE_4_FINGER_SINGLE_TAP = 37; // 0x25
@@ -10664,12 +10667,15 @@
field public static final String ACTION_PACKAGE_CHANGED = "android.intent.action.PACKAGE_CHANGED";
field public static final String ACTION_PACKAGE_DATA_CLEARED = "android.intent.action.PACKAGE_DATA_CLEARED";
field public static final String ACTION_PACKAGE_FIRST_LAUNCH = "android.intent.action.PACKAGE_FIRST_LAUNCH";
+ field public static final String ACTION_PACKAGE_FULLY_LOADED = "android.intent.action.PACKAGE_FULLY_LOADED";
field public static final String ACTION_PACKAGE_FULLY_REMOVED = "android.intent.action.PACKAGE_FULLY_REMOVED";
field @Deprecated public static final String ACTION_PACKAGE_INSTALL = "android.intent.action.PACKAGE_INSTALL";
field public static final String ACTION_PACKAGE_NEEDS_VERIFICATION = "android.intent.action.PACKAGE_NEEDS_VERIFICATION";
field public static final String ACTION_PACKAGE_REMOVED = "android.intent.action.PACKAGE_REMOVED";
field public static final String ACTION_PACKAGE_REPLACED = "android.intent.action.PACKAGE_REPLACED";
field public static final String ACTION_PACKAGE_RESTARTED = "android.intent.action.PACKAGE_RESTARTED";
+ field public static final String ACTION_PACKAGE_STARTABLE = "android.intent.action.PACKAGE_STARTABLE";
+ field public static final String ACTION_PACKAGE_UNSTARTABLE = "android.intent.action.PACKAGE_UNSTARTABLE";
field public static final String ACTION_PACKAGE_VERIFIED = "android.intent.action.PACKAGE_VERIFIED";
field public static final String ACTION_PASTE = "android.intent.action.PASTE";
field public static final String ACTION_PICK = "android.intent.action.PICK";
@@ -10834,6 +10840,7 @@
field public static final String EXTRA_TIMEZONE = "time-zone";
field public static final String EXTRA_TITLE = "android.intent.extra.TITLE";
field public static final String EXTRA_UID = "android.intent.extra.UID";
+ field public static final String EXTRA_UNSTARTABLE_REASON = "android.intent.extra.UNSTARTABLE_REASON";
field public static final String EXTRA_USER = "android.intent.extra.USER";
field public static final int FILL_IN_ACTION = 1; // 0x1
field public static final int FILL_IN_CATEGORIES = 4; // 0x4
@@ -12293,6 +12300,9 @@
field public static final int SYNCHRONOUS = 2; // 0x2
field @Nullable public static final java.util.List<java.security.cert.Certificate> TRUST_ALL;
field @NonNull public static final java.util.List<java.security.cert.Certificate> TRUST_NONE;
+ field public static final int UNSTARTABLE_REASON_CONNECTION_ERROR = 1; // 0x1
+ field public static final int UNSTARTABLE_REASON_INSUFFICIENT_STORAGE = 2; // 0x2
+ field public static final int UNSTARTABLE_REASON_UNKNOWN = 0; // 0x0
field public static final int VERIFICATION_ALLOW = 1; // 0x1
field public static final int VERIFICATION_REJECT = -1; // 0xffffffff
field public static final int VERSION_CODE_HIGHEST = -1; // 0xffffffff
@@ -24071,9 +24081,13 @@
method @IntRange(from=1, to=java.lang.Integer.MAX_VALUE) public int getMaxUpdates();
method @FloatRange(from=0, to=java.lang.Float.MAX_VALUE) public float getMinUpdateDistanceMeters();
method @IntRange(from=0) public long getMinUpdateIntervalMillis();
+ method public int getQuality();
method public void writeToParcel(@NonNull android.os.Parcel, int);
field @NonNull public static final android.os.Parcelable.Creator<android.location.LocationRequest> CREATOR;
field public static final long PASSIVE_INTERVAL = 9223372036854775807L; // 0x7fffffffffffffffL
+ field public static final int QUALITY_BALANCED_POWER_ACCURACY = 102; // 0x66
+ field public static final int QUALITY_HIGH_ACCURACY = 100; // 0x64
+ field public static final int QUALITY_LOW_POWER = 104; // 0x68
}
public static final class LocationRequest.Builder {
@@ -24086,6 +24100,7 @@
method @NonNull public android.location.LocationRequest.Builder setMaxUpdates(@IntRange(from=1, to=java.lang.Integer.MAX_VALUE) int);
method @NonNull public android.location.LocationRequest.Builder setMinUpdateDistanceMeters(@FloatRange(from=0, to=java.lang.Float.MAX_VALUE) float);
method @NonNull public android.location.LocationRequest.Builder setMinUpdateIntervalMillis(@IntRange(from=0) long);
+ method @NonNull public android.location.LocationRequest.Builder setQuality(int);
}
public interface OnNmeaMessageListener {
diff --git a/non-updatable-api/module-lib-current.txt b/non-updatable-api/module-lib-current.txt
index b19ce48..3c1d19f 100644
--- a/non-updatable-api/module-lib-current.txt
+++ b/non-updatable-api/module-lib-current.txt
@@ -1,10 +1,20 @@
// Signature format: 2.0
package android.app {
+ public class ActivityManager {
+ method @RequiresPermission(android.Manifest.permission.SET_ACTIVITY_WATCHER) public void addHomeVisibilityListener(@NonNull java.util.concurrent.Executor, @NonNull android.app.HomeVisibilityListener);
+ method @RequiresPermission(android.Manifest.permission.SET_ACTIVITY_WATCHER) public void removeHomeVisibilityListener(@NonNull android.app.HomeVisibilityListener);
+ }
+
public class AppOpsManager {
field public static final String OPSTR_NO_ISOLATED_STORAGE = "android:no_isolated_storage";
}
+ public abstract class HomeVisibilityListener {
+ ctor public HomeVisibilityListener();
+ method public abstract void onHomeVisibilityChanged(boolean);
+ }
+
public class NotificationManager {
method public boolean hasEnabledNotificationListener(@NonNull String, @NonNull android.os.UserHandle);
field public static final String ACTION_NOTIFICATION_LISTENER_ENABLED_CHANGED = "android.app.action.NOTIFICATION_LISTENER_ENABLED_CHANGED";
@@ -123,6 +133,18 @@
}
+package android.telephony {
+
+ public abstract class CellSignalStrength {
+ method public static int getNumSignalStrengthLevels();
+ }
+
+ public class TelephonyManager {
+ method @NonNull public static int[] getAllNetworkTypes();
+ }
+
+}
+
package android.util {
public class AtomicFile {
diff --git a/non-updatable-api/system-current.txt b/non-updatable-api/system-current.txt
index 75e038be..50062bf 100644
--- a/non-updatable-api/system-current.txt
+++ b/non-updatable-api/system-current.txt
@@ -122,6 +122,7 @@
field public static final String MANAGE_FACTORY_RESET_PROTECTION = "android.permission.MANAGE_FACTORY_RESET_PROTECTION";
field public static final String MANAGE_IPSEC_TUNNELS = "android.permission.MANAGE_IPSEC_TUNNELS";
field public static final String MANAGE_MUSIC_RECOGNITION = "android.permission.MANAGE_MUSIC_RECOGNITION";
+ field public static final String MANAGE_NOTIFICATION_LISTENERS = "android.permission.MANAGE_NOTIFICATION_LISTENERS";
field public static final String MANAGE_ONE_TIME_PERMISSION_SESSIONS = "android.permission.MANAGE_ONE_TIME_PERMISSION_SESSIONS";
field public static final String MANAGE_ROLE_HOLDERS = "android.permission.MANAGE_ROLE_HOLDERS";
field public static final String MANAGE_ROLLBACKS = "android.permission.MANAGE_ROLLBACKS";
@@ -674,8 +675,10 @@
public class NotificationManager {
method @NonNull public java.util.List<java.lang.String> getAllowedAssistantAdjustments();
method @Nullable public android.content.ComponentName getAllowedNotificationAssistant();
+ method @NonNull @RequiresPermission(android.Manifest.permission.MANAGE_NOTIFICATION_LISTENERS) public java.util.List<android.content.ComponentName> getEnabledNotificationListeners();
method public boolean isNotificationAssistantAccessGranted(@NonNull android.content.ComponentName);
method public void setNotificationAssistantAccessGranted(@Nullable android.content.ComponentName, boolean);
+ method @RequiresPermission(android.Manifest.permission.MANAGE_NOTIFICATION_LISTENERS) public void setNotificationListenerAccessGranted(@NonNull android.content.ComponentName, boolean);
field @RequiresPermission(android.Manifest.permission.STATUS_BAR_SERVICE) public static final String ACTION_CLOSE_NOTIFICATION_HANDLER_PANEL = "android.app.action.CLOSE_NOTIFICATION_HANDLER_PANEL";
field @RequiresPermission(android.Manifest.permission.STATUS_BAR_SERVICE) public static final String ACTION_OPEN_NOTIFICATION_HANDLER_PANEL = "android.app.action.OPEN_NOTIFICATION_HANDLER_PANEL";
field @RequiresPermission(android.Manifest.permission.STATUS_BAR_SERVICE) public static final String ACTION_TOGGLE_NOTIFICATION_HANDLER_PANEL = "android.app.action.TOGGLE_NOTIFICATION_HANDLER_PANEL";
@@ -4111,7 +4114,6 @@
method @Deprecated public long getInterval();
method @Deprecated public int getNumUpdates();
method @Deprecated @NonNull public String getProvider();
- method public int getQuality();
method @Deprecated public float getSmallestDisplacement();
method @NonNull public android.os.WorkSource getWorkSource();
method public boolean isHiddenFromAppOps();
@@ -4130,11 +4132,11 @@
method @Deprecated @NonNull public android.location.LocationRequest setQuality(int);
method @Deprecated @NonNull public android.location.LocationRequest setSmallestDisplacement(float);
method @Deprecated public void setWorkSource(@Nullable android.os.WorkSource);
- field public static final int ACCURACY_BLOCK = 102; // 0x66
- field public static final int ACCURACY_CITY = 104; // 0x68
- field public static final int ACCURACY_FINE = 100; // 0x64
- field public static final int POWER_HIGH = 203; // 0xcb
- field public static final int POWER_LOW = 201; // 0xc9
+ field @Deprecated public static final int ACCURACY_BLOCK = 102; // 0x66
+ field @Deprecated public static final int ACCURACY_CITY = 104; // 0x68
+ field @Deprecated public static final int ACCURACY_FINE = 100; // 0x64
+ field @Deprecated public static final int POWER_HIGH = 203; // 0xcb
+ field @Deprecated public static final int POWER_LOW = 201; // 0xc9
field @Deprecated public static final int POWER_NONE = 200; // 0xc8
}
@@ -4142,7 +4144,6 @@
method @NonNull @RequiresPermission(android.Manifest.permission.UPDATE_APP_OPS_STATS) public android.location.LocationRequest.Builder setHiddenFromAppOps(boolean);
method @NonNull @RequiresPermission(android.Manifest.permission.WRITE_SECURE_SETTINGS) public android.location.LocationRequest.Builder setLocationSettingsIgnored(boolean);
method @NonNull @RequiresPermission(android.Manifest.permission.LOCATION_HARDWARE) public android.location.LocationRequest.Builder setLowPower(boolean);
- method @NonNull public android.location.LocationRequest.Builder setQuality(int);
method @NonNull @RequiresPermission(android.Manifest.permission.UPDATE_DEVICE_STATS) public android.location.LocationRequest.Builder setWorkSource(@Nullable android.os.WorkSource);
}
@@ -4709,6 +4710,22 @@
field @NonNull public static final android.os.Parcelable.Creator<android.media.tv.DvbDeviceInfo> CREATOR;
}
+ public final class TunedInfo implements android.os.Parcelable {
+ method public int describeContents();
+ method public int getAppTag();
+ method public int getAppType();
+ method @Nullable public android.net.Uri getChannelUri();
+ method @NonNull public String getInputId();
+ method public boolean isForeground();
+ method public boolean isRecordingSession();
+ method public void writeToParcel(@NonNull android.os.Parcel, int);
+ field public static final int APP_TAG_SELF = 0; // 0x0
+ field public static final int APP_TYPE_NON_SYSTEM = 3; // 0x3
+ field public static final int APP_TYPE_SELF = 1; // 0x1
+ field public static final int APP_TYPE_SYSTEM = 2; // 0x2
+ field @NonNull public static final android.os.Parcelable.Creator<android.media.tv.TunedInfo> CREATOR;
+ }
+
public final class TvContentRatingSystemInfo implements android.os.Parcelable {
method public static android.media.tv.TvContentRatingSystemInfo createTvContentRatingSystemInfo(int, android.content.pm.ApplicationInfo);
method public int describeContents();
@@ -4824,6 +4841,7 @@
method @RequiresPermission(android.Manifest.permission.MODIFY_PARENTAL_CONTROLS) public void addBlockedRating(@NonNull android.media.tv.TvContentRating);
method @RequiresPermission(android.Manifest.permission.CAPTURE_TV_INPUT) public boolean captureFrame(String, android.view.Surface, android.media.tv.TvStreamConfig);
method @RequiresPermission(android.Manifest.permission.CAPTURE_TV_INPUT) public java.util.List<android.media.tv.TvStreamConfig> getAvailableTvStreamConfigList(String);
+ method @NonNull @RequiresPermission("com.android.providers.tv.permission.ACCESS_WATCHED_PROGRAMS") public java.util.List<android.media.tv.TunedInfo> getCurrentTunedInfos();
method @NonNull @RequiresPermission("android.permission.DVB_DEVICE") public java.util.List<android.media.tv.DvbDeviceInfo> getDvbDeviceList();
method @RequiresPermission(android.Manifest.permission.TV_INPUT_HARDWARE) public java.util.List<android.media.tv.TvInputHardwareInfo> getHardwareList();
method @RequiresPermission(android.Manifest.permission.READ_CONTENT_RATING_SYSTEMS) public java.util.List<android.media.tv.TvContentRatingSystemInfo> getTvContentRatingSystemList();
@@ -4849,6 +4867,10 @@
method public abstract void onStreamConfigChanged(android.media.tv.TvStreamConfig[]);
}
+ public abstract static class TvInputManager.TvInputCallback {
+ method public void onCurrentTunedInfosUpdated(@NonNull java.util.List<android.media.tv.TunedInfo>);
+ }
+
public abstract class TvInputService extends android.app.Service {
method @Nullable public android.media.tv.TvInputInfo onHardwareAdded(android.media.tv.TvInputHardwareInfo);
method @Nullable public String onHardwareRemoved(android.media.tv.TvInputHardwareInfo);
@@ -4976,6 +4998,7 @@
method @Nullable public android.media.tv.tuner.DemuxCapabilities getDemuxCapabilities();
method @Nullable public android.media.tv.tuner.frontend.FrontendInfo getFrontendInfo();
method @Nullable public android.media.tv.tuner.frontend.FrontendStatus getFrontendStatus(@NonNull int[]);
+ method public int linkFrontendToCiCam(int);
method @Nullable @RequiresPermission(android.Manifest.permission.ACCESS_TV_DESCRAMBLER) public android.media.tv.tuner.Descrambler openDescrambler();
method @Nullable public android.media.tv.tuner.dvr.DvrPlayback openDvrPlayback(long, @NonNull java.util.concurrent.Executor, @NonNull android.media.tv.tuner.dvr.OnPlaybackStatusChangedListener);
method @Nullable public android.media.tv.tuner.dvr.DvrRecorder openDvrRecorder(long, @NonNull java.util.concurrent.Executor, @NonNull android.media.tv.tuner.dvr.OnRecordStatusChangedListener);
@@ -4989,10 +5012,13 @@
method public void setResourceLostListener(@NonNull java.util.concurrent.Executor, @NonNull android.media.tv.tuner.Tuner.OnResourceLostListener);
method public void shareFrontendFromTuner(@NonNull android.media.tv.tuner.Tuner);
method public int tune(@NonNull android.media.tv.tuner.frontend.FrontendSettings);
+ method public int unlinkFrontendToCiCam(int);
method public void updateResourcePriority(int, int);
field public static final int INVALID_AV_SYNC_ID = -1; // 0xffffffff
field public static final int INVALID_FILTER_ID = -1; // 0xffffffff
field public static final long INVALID_FILTER_ID_64BIT = -1L; // 0xffffffffffffffffL
+ field public static final int INVALID_FRONTEND_SETTING_FREQUENCY = -1; // 0xffffffff
+ field public static final int INVALID_LTS_ID = -1; // 0xffffffff
field public static final int INVALID_MMTP_RECORD_EVENT_MPT_SEQUENCE_NUM = -1; // 0xffffffff
field public static final int INVALID_STREAM_ID = 65535; // 0xffff
field public static final long INVALID_TIMESTAMP = -1L; // 0xffffffffffffffffL
@@ -5205,16 +5231,19 @@
method @NonNull public static android.media.tv.tuner.filter.IpFilterConfiguration.Builder builder();
method @NonNull @Size(min=4, max=16) public byte[] getDstIpAddress();
method public int getDstPort();
+ method public int getIpFilterContextId();
method @NonNull @Size(min=4, max=16) public byte[] getSrcIpAddress();
method public int getSrcPort();
method public int getType();
method public boolean isPassthrough();
+ field public static final int INVALID_IP_FILTER_CONTEXT_ID = -1; // 0xffffffff
}
public static final class IpFilterConfiguration.Builder {
method @NonNull public android.media.tv.tuner.filter.IpFilterConfiguration build();
method @NonNull public android.media.tv.tuner.filter.IpFilterConfiguration.Builder setDstIpAddress(@NonNull byte[]);
method @NonNull public android.media.tv.tuner.filter.IpFilterConfiguration.Builder setDstPort(int);
+ method @NonNull public android.media.tv.tuner.filter.IpFilterConfiguration.Builder setIpFilterContextId(int);
method @NonNull public android.media.tv.tuner.filter.IpFilterConfiguration.Builder setPassthrough(boolean);
method @NonNull public android.media.tv.tuner.filter.IpFilterConfiguration.Builder setSettings(@Nullable android.media.tv.tuner.filter.Settings);
method @NonNull public android.media.tv.tuner.filter.IpFilterConfiguration.Builder setSrcIpAddress(@NonNull byte[]);
@@ -5434,9 +5463,13 @@
public class AnalogFrontendSettings extends android.media.tv.tuner.frontend.FrontendSettings {
method @NonNull public static android.media.tv.tuner.frontend.AnalogFrontendSettings.Builder builder();
+ method public int getAftFlag();
method public int getSifStandard();
method public int getSignalType();
method public int getType();
+ field public static final int AFT_FLAG_FALSE = 2; // 0x2
+ field public static final int AFT_FLAG_TRUE = 1; // 0x1
+ field public static final int AFT_FLAG_UNDEFINED = 0; // 0x0
field public static final int SIF_AUTO = 1; // 0x1
field public static final int SIF_BG = 2; // 0x2
field public static final int SIF_BG_A2 = 4; // 0x4
@@ -5469,6 +5502,7 @@
public static class AnalogFrontendSettings.Builder {
method @NonNull public android.media.tv.tuner.frontend.AnalogFrontendSettings build();
+ method @NonNull public android.media.tv.tuner.frontend.AnalogFrontendSettings.Builder setAftFlag(int);
method @IntRange(from=1) @NonNull public android.media.tv.tuner.frontend.AnalogFrontendSettings.Builder setFrequency(int);
method @NonNull public android.media.tv.tuner.frontend.AnalogFrontendSettings.Builder setSifStandard(int);
method @NonNull public android.media.tv.tuner.frontend.AnalogFrontendSettings.Builder setSignalType(int);
@@ -5598,6 +5632,7 @@
method public int getOuterFec();
method public int getSpectralInversion();
method public int getSymbolRate();
+ method public int getTimeInterleaveMode();
method public int getType();
field public static final int ANNEX_A = 1; // 0x1
field public static final int ANNEX_B = 2; // 0x2
@@ -5616,6 +5651,17 @@
field public static final int SPECTRAL_INVERSION_INVERTED = 2; // 0x2
field public static final int SPECTRAL_INVERSION_NORMAL = 1; // 0x1
field public static final int SPECTRAL_INVERSION_UNDEFINED = 0; // 0x0
+ field public static final int TIME_INTERLEAVE_MODE_128_1_0 = 2; // 0x2
+ field public static final int TIME_INTERLEAVE_MODE_128_1_1 = 4; // 0x4
+ field public static final int TIME_INTERLEAVE_MODE_128_2 = 128; // 0x80
+ field public static final int TIME_INTERLEAVE_MODE_128_3 = 256; // 0x100
+ field public static final int TIME_INTERLEAVE_MODE_128_4 = 512; // 0x200
+ field public static final int TIME_INTERLEAVE_MODE_16_8 = 32; // 0x20
+ field public static final int TIME_INTERLEAVE_MODE_32_4 = 16; // 0x10
+ field public static final int TIME_INTERLEAVE_MODE_64_2 = 8; // 0x8
+ field public static final int TIME_INTERLEAVE_MODE_8_16 = 64; // 0x40
+ field public static final int TIME_INTERLEAVE_MODE_AUTO = 1; // 0x1
+ field public static final int TIME_INTERLEAVE_MODE_UNDEFINED = 0; // 0x0
}
public static class DvbcFrontendSettings.Builder {
@@ -5627,6 +5673,7 @@
method @NonNull public android.media.tv.tuner.frontend.DvbcFrontendSettings.Builder setOuterFec(int);
method @NonNull public android.media.tv.tuner.frontend.DvbcFrontendSettings.Builder setSpectralInversion(int);
method @NonNull public android.media.tv.tuner.frontend.DvbcFrontendSettings.Builder setSymbolRate(int);
+ method @NonNull public android.media.tv.tuner.frontend.DvbcFrontendSettings.Builder setTimeInterleaveMode(int);
}
public class DvbsCodeRate {
@@ -5658,6 +5705,7 @@
method public int getModulation();
method public int getPilot();
method public int getRolloff();
+ method public int getScanType();
method public int getStandard();
method public int getSymbolRate();
method public int getType();
@@ -5688,6 +5736,11 @@
field public static final int ROLLOFF_0_35 = 1; // 0x1
field public static final int ROLLOFF_0_5 = 6; // 0x6
field public static final int ROLLOFF_UNDEFINED = 0; // 0x0
+ field public static final int SCAN_TYPE_DIRECT = 1; // 0x1
+ field public static final int SCAN_TYPE_DISEQC = 2; // 0x2
+ field public static final int SCAN_TYPE_JESS = 4; // 0x4
+ field public static final int SCAN_TYPE_UNDEFINED = 0; // 0x0
+ field public static final int SCAN_TYPE_UNICABLE = 3; // 0x3
field public static final int STANDARD_AUTO = 1; // 0x1
field public static final int STANDARD_S = 2; // 0x2
field public static final int STANDARD_S2 = 4; // 0x4
@@ -5705,6 +5758,7 @@
method @NonNull public android.media.tv.tuner.frontend.DvbsFrontendSettings.Builder setModulation(int);
method @NonNull public android.media.tv.tuner.frontend.DvbsFrontendSettings.Builder setPilot(int);
method @NonNull public android.media.tv.tuner.frontend.DvbsFrontendSettings.Builder setRolloff(int);
+ method @NonNull public android.media.tv.tuner.frontend.DvbsFrontendSettings.Builder setScanType(int);
method @NonNull public android.media.tv.tuner.frontend.DvbsFrontendSettings.Builder setStandard(int);
method @NonNull public android.media.tv.tuner.frontend.DvbsFrontendSettings.Builder setSymbolRate(int);
method @NonNull public android.media.tv.tuner.frontend.DvbsFrontendSettings.Builder setVcmMode(int);
@@ -5757,10 +5811,14 @@
field public static final int CODERATE_AUTO = 1; // 0x1
field public static final int CODERATE_UNDEFINED = 0; // 0x0
field public static final int CONSTELLATION_16QAM = 4; // 0x4
+ field public static final int CONSTELLATION_16QAM_R = 64; // 0x40
field public static final int CONSTELLATION_256QAM = 16; // 0x10
+ field public static final int CONSTELLATION_256QAM_R = 256; // 0x100
field public static final int CONSTELLATION_64QAM = 8; // 0x8
+ field public static final int CONSTELLATION_64QAM_R = 128; // 0x80
field public static final int CONSTELLATION_AUTO = 1; // 0x1
field public static final int CONSTELLATION_QPSK = 2; // 0x2
+ field public static final int CONSTELLATION_QPSK_R = 32; // 0x20
field public static final int CONSTELLATION_UNDEFINED = 0; // 0x0
field public static final int GUARD_INTERVAL_19_128 = 64; // 0x40
field public static final int GUARD_INTERVAL_19_256 = 128; // 0x80
@@ -5794,6 +5852,9 @@
field public static final int TRANSMISSION_MODE_4K = 8; // 0x8
field public static final int TRANSMISSION_MODE_8K = 4; // 0x4
field public static final int TRANSMISSION_MODE_AUTO = 1; // 0x1
+ field public static final int TRANSMISSION_MODE_EXTENDED_16K = 256; // 0x100
+ field public static final int TRANSMISSION_MODE_EXTENDED_32K = 512; // 0x200
+ field public static final int TRANSMISSION_MODE_EXTENDED_8K = 128; // 0x80
field public static final int TRANSMISSION_MODE_UNDEFINED = 0; // 0x0
}
@@ -5831,8 +5892,12 @@
}
public abstract class FrontendSettings {
+ method public int getEndFrequency();
method public int getFrequency();
+ method public int getFrontendSpectralInversion();
method public abstract int getType();
+ method @IntRange(from=1) public void setEndFrequency(int);
+ method public void setSpectralInversion(int);
field public static final long FEC_11_15 = 4194304L; // 0x400000L
field public static final long FEC_11_20 = 8388608L; // 0x800000L
field public static final long FEC_11_45 = 16777216L; // 0x1000000L
@@ -5870,6 +5935,9 @@
field public static final long FEC_9_20 = 2097152L; // 0x200000L
field public static final long FEC_AUTO = 1L; // 0x1L
field public static final long FEC_UNDEFINED = 0L; // 0x0L
+ field public static final int FRONTEND_SPECTRAL_INVERSION_INVERTED = 2; // 0x2
+ field public static final int FRONTEND_SPECTRAL_INVERSION_NORMAL = 1; // 0x1
+ field public static final int FRONTEND_SPECTRAL_INVERSION_UNDEFINED = 0; // 0x0
field public static final int TYPE_ANALOG = 1; // 0x1
field public static final int TYPE_ATSC = 2; // 0x2
field public static final int TYPE_ATSC3 = 3; // 0x3
@@ -9899,6 +9967,25 @@
field public static final String MBMS_STREAMING_SERVICE_ACTION = "android.telephony.action.EmbmsStreaming";
}
+ public final class ModemActivityInfo implements android.os.Parcelable {
+ method public int describeContents();
+ method @NonNull public android.telephony.ModemActivityInfo getDelta(@NonNull android.telephony.ModemActivityInfo);
+ method public long getIdleTimeMillis();
+ method public static int getNumTxPowerLevels();
+ method public long getReceiveTimeMillis();
+ method public long getSleepTimeMillis();
+ method public long getTimestampMillis();
+ method public long getTransmitDurationMillisAtPowerLevel(int);
+ method @NonNull public android.util.Range<java.lang.Integer> getTransmitPowerRange(int);
+ method public void writeToParcel(@NonNull android.os.Parcel, int);
+ field @NonNull public static final android.os.Parcelable.Creator<android.telephony.ModemActivityInfo> CREATOR;
+ field public static final int TX_POWER_LEVEL_0 = 0; // 0x0
+ field public static final int TX_POWER_LEVEL_1 = 1; // 0x1
+ field public static final int TX_POWER_LEVEL_2 = 2; // 0x2
+ field public static final int TX_POWER_LEVEL_3 = 3; // 0x3
+ field public static final int TX_POWER_LEVEL_4 = 4; // 0x4
+ }
+
public final class NetworkRegistrationInfo implements android.os.Parcelable {
method @Nullable public android.telephony.DataSpecificRegistrationInfo getDataSpecificInfo();
method public int getRegistrationState();
diff --git a/packages/FusedLocation/src/com/android/location/fused/FusedLocationProvider.java b/packages/FusedLocation/src/com/android/location/fused/FusedLocationProvider.java
index 900e68d..6827d6e 100644
--- a/packages/FusedLocation/src/com/android/location/fused/FusedLocationProvider.java
+++ b/packages/FusedLocation/src/com/android/location/fused/FusedLocationProvider.java
@@ -19,6 +19,9 @@
import static android.content.Intent.ACTION_USER_SWITCHED;
import static android.location.LocationManager.GPS_PROVIDER;
import static android.location.LocationManager.NETWORK_PROVIDER;
+import static android.location.LocationRequest.QUALITY_LOW_POWER;
+
+import static com.android.location.provider.ProviderRequestUnbundled.INTERVAL_DISABLED;
import android.annotation.Nullable;
import android.content.BroadcastReceiver;
@@ -35,7 +38,6 @@
import com.android.internal.annotations.GuardedBy;
import com.android.internal.location.ProviderRequest;
import com.android.location.provider.LocationProviderBase;
-import com.android.location.provider.LocationRequestUnbundled;
import com.android.location.provider.ProviderPropertiesUnbundled;
import com.android.location.provider.ProviderRequestUnbundled;
@@ -147,8 +149,8 @@
mRequest = new ProviderRequestUnbundled(ProviderRequest.EMPTY_REQUEST);
mWorkSource = new WorkSource();
- mGpsInterval = Long.MAX_VALUE;
- mNetworkInterval = Long.MAX_VALUE;
+ mGpsInterval = INTERVAL_DISABLED;
+ mNetworkInterval = INTERVAL_DISABLED;
}
void start() {
@@ -175,30 +177,9 @@
@GuardedBy("mLock")
private void updateRequirementsLocked() {
- long gpsInterval = Long.MAX_VALUE;
- long networkInterval = Long.MAX_VALUE;
- if (mRequest.getReportLocation()) {
- for (LocationRequestUnbundled request : mRequest.getLocationRequests()) {
- switch (request.getQuality()) {
- case LocationRequestUnbundled.ACCURACY_FINE:
- case LocationRequestUnbundled.ACCURACY_BLOCK:
- case LocationRequestUnbundled.POWER_HIGH:
- if (request.getInterval() < gpsInterval) {
- gpsInterval = request.getInterval();
- }
- if (request.getInterval() < networkInterval) {
- networkInterval = request.getInterval();
- }
- break;
- case LocationRequestUnbundled.ACCURACY_CITY:
- case LocationRequestUnbundled.POWER_LOW:
- if (request.getInterval() < networkInterval) {
- networkInterval = request.getInterval();
- }
- break;
- }
- }
- }
+ long gpsInterval = mRequest.getQuality() < QUALITY_LOW_POWER ? mRequest.getInterval()
+ : INTERVAL_DISABLED;
+ long networkInterval = mRequest.getInterval();
if (gpsInterval != mGpsInterval) {
resetProviderRequestLocked(GPS_PROVIDER, mGpsInterval, gpsInterval, mGpsListener);
@@ -214,11 +195,12 @@
@GuardedBy("mLock")
private void resetProviderRequestLocked(String provider, long oldInterval, long newInterval,
LocationListener listener) {
- if (oldInterval != Long.MAX_VALUE) {
+ if (oldInterval != INTERVAL_DISABLED && newInterval == INTERVAL_DISABLED) {
mLocationManager.removeUpdates(listener);
}
- if (newInterval != Long.MAX_VALUE) {
+ if (newInterval != INTERVAL_DISABLED) {
LocationRequest request = new LocationRequest.Builder(newInterval)
+ .setQuality(mRequest.getQuality())
.setLocationSettingsIgnored(mRequest.isLocationSettingsIgnored())
.setWorkSource(mWorkSource)
.build();
@@ -254,10 +236,10 @@
void dump(PrintWriter writer) {
synchronized (mLock) {
writer.println("request: " + mRequest);
- if (mGpsInterval != Long.MAX_VALUE) {
+ if (mGpsInterval != INTERVAL_DISABLED) {
writer.println(" gps interval: " + mGpsInterval);
}
- if (mNetworkInterval != Long.MAX_VALUE) {
+ if (mNetworkInterval != INTERVAL_DISABLED) {
writer.println(" network interval: " + mNetworkInterval);
}
if (mGpsLocation != null) {
diff --git a/packages/FusedLocation/test/src/com/android/location/fused/tests/FusedLocationServiceTest.java b/packages/FusedLocation/test/src/com/android/location/fused/tests/FusedLocationServiceTest.java
index d3aa977..61349d9 100644
--- a/packages/FusedLocation/test/src/com/android/location/fused/tests/FusedLocationServiceTest.java
+++ b/packages/FusedLocation/test/src/com/android/location/fused/tests/FusedLocationServiceTest.java
@@ -48,7 +48,6 @@
import java.io.ByteArrayOutputStream;
import java.io.FileInputStream;
import java.io.IOException;
-import java.util.Collections;
import java.util.Random;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.TimeUnit;
@@ -60,7 +59,6 @@
private static final long TIMEOUT_MS = 5000;
- private Context mContext;
private Random mRandom;
private LocationManager mLocationManager;
@@ -72,15 +70,15 @@
long seed = System.currentTimeMillis();
Log.i(TAG, "location seed: " + seed);
- mContext = InstrumentationRegistry.getTargetContext();
+ Context context = InstrumentationRegistry.getTargetContext();
mRandom = new Random(seed);
- mLocationManager = mContext.getSystemService(LocationManager.class);
+ mLocationManager = context.getSystemService(LocationManager.class);
setMockLocation(true);
mManager = new LocationProviderManagerCapture();
mProvider = ILocationProvider.Stub.asInterface(
- new FusedLocationProvider(mContext).getBinder());
+ new FusedLocationProvider(context).getBinder());
mProvider.setLocationProviderManager(mManager);
mLocationManager.addTestProvider(NETWORK_PROVIDER,
@@ -118,12 +116,9 @@
@Test
public void testNetworkRequest() throws Exception {
- LocationRequest request = new LocationRequest.Builder(1000).build();
-
mProvider.setRequest(
new ProviderRequest.Builder()
.setIntervalMillis(1000)
- .setLocationRequests(Collections.singletonList(request))
.build(),
new WorkSource());
@@ -135,14 +130,10 @@
@Test
public void testGpsRequest() throws Exception {
- LocationRequest request = new LocationRequest.Builder(1000)
- .setQuality(LocationRequest.POWER_HIGH)
- .build();
-
mProvider.setRequest(
new ProviderRequest.Builder()
+ .setQuality(LocationRequest.QUALITY_HIGH_ACCURACY)
.setIntervalMillis(1000)
- .setLocationRequests(Collections.singletonList(request))
.build(),
new WorkSource());
diff --git a/packages/PrintSpooler/src/com/android/printspooler/ui/FusedPrintersProvider.java b/packages/PrintSpooler/src/com/android/printspooler/ui/FusedPrintersProvider.java
index 8e140ca..83974af 100644
--- a/packages/PrintSpooler/src/com/android/printspooler/ui/FusedPrintersProvider.java
+++ b/packages/PrintSpooler/src/com/android/printspooler/ui/FusedPrintersProvider.java
@@ -254,7 +254,7 @@
mLocationManager.requestLocationUpdates(
LocationManager.FUSED_PROVIDER,
new LocationRequest.Builder(LOCATION_UPDATE_MS)
- .setQuality(LocationRequest.POWER_LOW)
+ .setQuality(LocationRequest.QUALITY_LOW_POWER)
.build(),
new HandlerExecutor(new Handler(Looper.getMainLooper())),
this);
diff --git a/packages/Shell/AndroidManifest.xml b/packages/Shell/AndroidManifest.xml
index bba29db..5f018a0 100644
--- a/packages/Shell/AndroidManifest.xml
+++ b/packages/Shell/AndroidManifest.xml
@@ -335,6 +335,9 @@
<!-- Permission required for CTS test - android.server.biometrics -->
<uses-permission android:name="android.permission.TEST_BIOMETRIC" />
+ <!-- Permissions required for CTS test - NotificationManagerTest -->
+ <uses-permission android:name="android.permission.MANAGE_NOTIFICATION_LISTENERS" />
+
<application android:label="@string/app_label"
android:theme="@android:style/Theme.DeviceDefault.DayNight"
android:defaultToDeviceProtectedStorage="true"
diff --git a/packages/SystemUI/res/values/dimens.xml b/packages/SystemUI/res/values/dimens.xml
index 7cbbaf9..26b3ab8 100644
--- a/packages/SystemUI/res/values/dimens.xml
+++ b/packages/SystemUI/res/values/dimens.xml
@@ -1217,7 +1217,7 @@
<!-- Interior padding of the message bubble -->
<dimen name="bubble_message_padding">4dp</dimen>
<!-- Offset between bubbles in their stacked position. -->
- <dimen name="bubble_stack_offset">5dp</dimen>
+ <dimen name="bubble_stack_offset">10dp</dimen>
<!-- How far offscreen the bubble stack rests. Cuts off padding and part of icon bitmap. -->
<dimen name="bubble_stack_offscreen">9dp</dimen>
<!-- How far down the screen the stack starts. -->
diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/system/SyncRtSurfaceTransactionApplierCompat.java b/packages/SystemUI/shared/src/com/android/systemui/shared/system/SyncRtSurfaceTransactionApplierCompat.java
index 86129e0..70021b6 100644
--- a/packages/SystemUI/shared/src/com/android/systemui/shared/system/SyncRtSurfaceTransactionApplierCompat.java
+++ b/packages/SystemUI/shared/src/com/android/systemui/shared/system/SyncRtSurfaceTransactionApplierCompat.java
@@ -65,7 +65,7 @@
public SyncRtSurfaceTransactionApplierCompat(View targetView) {
mTargetViewRootImpl = targetView != null ? targetView.getViewRootImpl() : null;
mBarrierSurfaceControl = mTargetViewRootImpl != null
- ? mTargetViewRootImpl.getRenderSurfaceControl() : null;
+ ? mTargetViewRootImpl.getSurfaceControl() : null;
mApplyHandler = new Handler(new Callback() {
@Override
diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/system/ViewRootImplCompat.java b/packages/SystemUI/shared/src/com/android/systemui/shared/system/ViewRootImplCompat.java
index 73783ae..4a28d56 100644
--- a/packages/SystemUI/shared/src/com/android/systemui/shared/system/ViewRootImplCompat.java
+++ b/packages/SystemUI/shared/src/com/android/systemui/shared/system/ViewRootImplCompat.java
@@ -34,10 +34,6 @@
}
public SurfaceControl getRenderSurfaceControl() {
- return mViewRoot == null ? null : mViewRoot.getRenderSurfaceControl();
- }
-
- public SurfaceControl getSurfaceControl() {
return mViewRoot == null ? null : mViewRoot.getSurfaceControl();
}
diff --git a/packages/SystemUI/src/com/android/systemui/SlicePermissionActivity.java b/packages/SystemUI/src/com/android/systemui/SlicePermissionActivity.java
index 2365f12..47adffc 100644
--- a/packages/SystemUI/src/com/android/systemui/SlicePermissionActivity.java
+++ b/packages/SystemUI/src/com/android/systemui/SlicePermissionActivity.java
@@ -111,9 +111,7 @@
final String providerPkg = getIntent().getStringExtra("provider_pkg");
if (providerPkg == null || mProviderPkg.equals(providerPkg)) return;
final String callingPkg = getCallingPkg();
- EventLog.writeEvent(0x534e4554, "159145361", getUid(callingPkg), String.format(
- "pkg %s (disguised as %s) attempted to request permission to show %s slices in %s",
- callingPkg, providerPkg, mProviderPkg, mCallingPkg));
+ EventLog.writeEvent(0x534e4554, "159145361", getUid(callingPkg));
}
@Nullable
diff --git a/packages/SystemUI/src/com/android/systemui/accessibility/WindowMagnificationController.java b/packages/SystemUI/src/com/android/systemui/accessibility/WindowMagnificationController.java
index c3474bb..340ca04 100644
--- a/packages/SystemUI/src/com/android/systemui/accessibility/WindowMagnificationController.java
+++ b/packages/SystemUI/src/com/android/systemui/accessibility/WindowMagnificationController.java
@@ -249,8 +249,8 @@
if ((configDiff & ActivityInfo.CONFIG_DENSITY) != 0) {
updateDimensions();
if (isWindowVisible()) {
- mWm.removeView(mMirrorView);
- createMirrorWindow();
+ deleteWindowMagnification();
+ enableWindowMagnification(Float.NaN, Float.NaN, Float.NaN);
}
} else if ((configDiff & ActivityInfo.CONFIG_ORIENTATION) != 0) {
onRotate();
diff --git a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleFlyoutView.java b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleFlyoutView.java
index 69f7828..009114f 100644
--- a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleFlyoutView.java
+++ b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleFlyoutView.java
@@ -18,6 +18,8 @@
import static android.graphics.Paint.ANTI_ALIAS_FLAG;
import static android.graphics.Paint.FILTER_BITMAP_FLAG;
+import static com.android.systemui.Interpolators.ALPHA_IN;
+import static com.android.systemui.Interpolators.ALPHA_OUT;
import android.animation.ArgbEvaluator;
import android.content.Context;
@@ -56,6 +58,11 @@
/** Max width of the flyout, in terms of percent of the screen width. */
private static final float FLYOUT_MAX_WIDTH_PERCENT = .6f;
+ /** Translation Y of fade animation. */
+ private static final float FLYOUT_FADE_Y = 40f;
+
+ private static final long FLYOUT_FADE_DURATION = 200L;
+
private final int mFlyoutPadding;
private final int mFlyoutSpaceFromBubble;
private final int mPointerSize;
@@ -104,6 +111,9 @@
/** The bounds of the flyout background, kept up to date as it transitions to the 'new' dot. */
private final RectF mBgRect = new RectF();
+ /** The y position of the flyout, relative to the top of the screen. */
+ private float mFlyoutY = 0f;
+
/**
* Percent progress in the transition from flyout to 'new' dot. These two values are the inverse
* of each other (if we're 40% transitioned to the dot, we're 60% flyout), but it makes the code
@@ -221,18 +231,33 @@
mSenderText.setTextSize(TypedValue.COMPLEX_UNIT_PX, newFontSize);
}
- /** Configures the flyout, collapsed into to dot form. */
- void setupFlyoutStartingAsDot(
- Bubble.FlyoutMessage flyoutMessage,
- PointF stackPos,
- float parentWidth,
- boolean arrowPointingLeft,
- int dotColor,
- @Nullable Runnable onLayoutComplete,
- @Nullable Runnable onHide,
- float[] dotCenter,
- boolean hideDot) {
+ /*
+ * Fade animation for consecutive flyouts.
+ */
+ void animateUpdate(Bubble.FlyoutMessage flyoutMessage, float parentWidth, float stackY) {
+ fade(false /* in */);
+ updateFlyoutMessage(flyoutMessage, parentWidth);
+ // Wait for TextViews to layout with updated height.
+ post(() -> {
+ mFlyoutY = stackY + (mBubbleSize - mFlyoutTextContainer.getHeight()) / 2f;
+ fade(true /* in */);
+ });
+ }
+ private void fade(boolean in) {
+ setAlpha(in ? 0f : 1f);
+ setTranslationY(in ? mFlyoutY : mFlyoutY + FLYOUT_FADE_Y);
+ animate()
+ .alpha(in ? 1f : 0f)
+ .setDuration(FLYOUT_FADE_DURATION)
+ .setInterpolator(in ? ALPHA_IN : ALPHA_OUT);
+ animate()
+ .translationY(in ? mFlyoutY : mFlyoutY - FLYOUT_FADE_Y)
+ .setDuration(FLYOUT_FADE_DURATION)
+ .setInterpolator(in ? ALPHA_IN : ALPHA_OUT);
+ }
+
+ private void updateFlyoutMessage(Bubble.FlyoutMessage flyoutMessage, float parentWidth) {
final Drawable senderAvatar = flyoutMessage.senderAvatar;
if (senderAvatar != null && flyoutMessage.isGroupChat) {
mSenderAvatar.setVisibility(VISIBLE);
@@ -256,6 +281,27 @@
mSenderText.setVisibility(GONE);
}
+ // Set the flyout TextView's max width in terms of percent, and then subtract out the
+ // padding so that the entire flyout view will be the desired width (rather than the
+ // TextView being the desired width + extra padding).
+ mMessageText.setMaxWidth(maxTextViewWidth);
+ mMessageText.setText(flyoutMessage.message);
+ }
+
+ /** Configures the flyout, collapsed into dot form. */
+ void setupFlyoutStartingAsDot(
+ Bubble.FlyoutMessage flyoutMessage,
+ PointF stackPos,
+ float parentWidth,
+ boolean arrowPointingLeft,
+ int dotColor,
+ @Nullable Runnable onLayoutComplete,
+ @Nullable Runnable onHide,
+ float[] dotCenter,
+ boolean hideDot) {
+
+ updateFlyoutMessage(flyoutMessage, parentWidth);
+
mArrowPointingLeft = arrowPointingLeft;
mDotColor = dotColor;
mOnHide = onHide;
@@ -263,24 +309,12 @@
setCollapsePercent(1f);
- // Set the flyout TextView's max width in terms of percent, and then subtract out the
- // padding so that the entire flyout view will be the desired width (rather than the
- // TextView being the desired width + extra padding).
- mMessageText.setMaxWidth(maxTextViewWidth);
- mMessageText.setText(flyoutMessage.message);
-
- // Wait for the TextView to lay out so we know its line count.
+ // Wait for TextViews to layout with updated height.
post(() -> {
- float restingTranslationY;
- // Multi line flyouts get top-aligned to the bubble.
- if (mMessageText.getLineCount() > 1) {
- restingTranslationY = stackPos.y + mBubbleIconTopPadding;
- } else {
- // Single line flyouts are vertically centered with respect to the bubble.
- restingTranslationY =
- stackPos.y + (mBubbleSize - mFlyoutTextContainer.getHeight()) / 2f;
- }
- setTranslationY(restingTranslationY);
+ // Flyout is vertically centered with respect to the bubble.
+ mFlyoutY =
+ stackPos.y + (mBubbleSize - mFlyoutTextContainer.getHeight()) / 2f;
+ setTranslationY(mFlyoutY);
// Calculate the translation required to position the flyout next to the bubble stack,
// with the desired padding.
@@ -300,7 +334,7 @@
final float dotPositionY = stackPos.y + mDotCenter[1] - adjustmentForScaleAway;
final float distanceFromFlyoutLeftToDotCenterX = mRestingTranslationX - dotPositionX;
- final float distanceFromLayoutTopToDotCenterY = restingTranslationY - dotPositionY;
+ final float distanceFromLayoutTopToDotCenterY = mFlyoutY - dotPositionY;
mTranslationXWhenDot = -distanceFromFlyoutLeftToDotCenterX;
mTranslationYWhenDot = -distanceFromLayoutTopToDotCenterY;
diff --git a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleStackView.java b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleStackView.java
index e2674de..431719f 100644
--- a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleStackView.java
+++ b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleStackView.java
@@ -2171,11 +2171,7 @@
return getStatusBarHeight() + mBubbleSize + mBubblePaddingTop;
}
- /**
- * Animates in the flyout for the given bubble, if available, and then hides it after some time.
- */
- @VisibleForTesting
- void animateInFlyoutForBubble(Bubble bubble) {
+ private boolean shouldShowFlyout(Bubble bubble) {
Bubble.FlyoutMessage flyoutMessage = bubble.getFlyoutMessage();
final BadgedImageView bubbleView = bubble.getIconView();
if (flyoutMessage == null
@@ -2187,11 +2183,22 @@
|| mIsGestureInProgress
|| mBubbleToExpandAfterFlyoutCollapse != null
|| bubbleView == null) {
- if (bubbleView != null) {
+ if (bubbleView != null && mFlyout.getVisibility() != VISIBLE) {
bubbleView.removeDotSuppressionFlag(BadgedImageView.SuppressionFlag.FLYOUT_VISIBLE);
}
// Skip the message if none exists, we're expanded or animating expansion, or we're
// about to expand a bubble from the previous tapped flyout, or if bubble view is null.
+ return false;
+ }
+ return true;
+ }
+
+ /**
+ * Animates in the flyout for the given bubble, if available, and then hides it after some time.
+ */
+ @VisibleForTesting
+ void animateInFlyoutForBubble(Bubble bubble) {
+ if (!shouldShowFlyout(bubble)) {
return;
}
@@ -2209,25 +2216,22 @@
}
// Stop suppressing the dot now that the flyout has morphed into the dot.
- bubbleView.removeDotSuppressionFlag(
+ bubble.getIconView().removeDotSuppressionFlag(
BadgedImageView.SuppressionFlag.FLYOUT_VISIBLE);
- mFlyout.setVisibility(INVISIBLE);
-
// Hide the stack after a delay, if needed.
updateTemporarilyInvisibleAnimation(false /* hideImmediately */);
};
- mFlyout.setVisibility(INVISIBLE);
// Suppress the dot when we are animating the flyout.
- bubbleView.addDotSuppressionFlag(
+ bubble.getIconView().addDotSuppressionFlag(
BadgedImageView.SuppressionFlag.FLYOUT_VISIBLE);
// Start flyout expansion. Post in case layout isn't complete and getWidth returns 0.
post(() -> {
// An auto-expanding bubble could have been posted during the time it takes to
// layout.
- if (isExpanded()) {
+ if (isExpanded() || bubble.getIconView() == null) {
return;
}
final Runnable expandFlyoutAfterDelay = () -> {
@@ -2244,18 +2248,21 @@
mFlyout.postDelayed(mAnimateInFlyout, 200);
};
- if (bubble.getIconView() == null) {
- return;
- }
- mFlyout.setupFlyoutStartingAsDot(flyoutMessage,
- mStackAnimationController.getStackPosition(), getWidth(),
- mStackAnimationController.isStackOnLeftSide(),
- bubble.getIconView().getDotColor() /* dotColor */,
- expandFlyoutAfterDelay /* onLayoutComplete */,
- mAfterFlyoutHidden,
- bubble.getIconView().getDotCenter(),
- !bubble.showDot());
+ if (mFlyout.getVisibility() == View.VISIBLE) {
+ mFlyout.animateUpdate(bubble.getFlyoutMessage(), getWidth(),
+ mStackAnimationController.getStackPosition().y);
+ } else {
+ mFlyout.setVisibility(INVISIBLE);
+ mFlyout.setupFlyoutStartingAsDot(bubble.getFlyoutMessage(),
+ mStackAnimationController.getStackPosition(), getWidth(),
+ mStackAnimationController.isStackOnLeftSide(),
+ bubble.getIconView().getDotColor() /* dotColor */,
+ expandFlyoutAfterDelay /* onLayoutComplete */,
+ mAfterFlyoutHidden,
+ bubble.getIconView().getDotCenter(),
+ !bubble.showDot());
+ }
mFlyout.bringToFront();
});
mFlyout.removeCallbacks(mHideFlyout);
diff --git a/packages/SystemUI/src/com/android/systemui/bubbles/StackEducationView.kt b/packages/SystemUI/src/com/android/systemui/bubbles/StackEducationView.kt
index 9e7a2fb..216df2e 100644
--- a/packages/SystemUI/src/com/android/systemui/bubbles/StackEducationView.kt
+++ b/packages/SystemUI/src/com/android/systemui/bubbles/StackEducationView.kt
@@ -128,7 +128,7 @@
private fun setShouldShow(shouldShow: Boolean) {
context.getSharedPreferences(context.packageName, Context.MODE_PRIVATE)
- .edit().putBoolean(PREF_MANAGED_EDUCATION, !shouldShow).apply()
+ .edit().putBoolean(PREF_STACK_EDUCATION, !shouldShow).apply()
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/bubbles/animation/ExpandedAnimationController.java b/packages/SystemUI/src/com/android/systemui/bubbles/animation/ExpandedAnimationController.java
index fd73207..7fdc019 100644
--- a/packages/SystemUI/src/com/android/systemui/bubbles/animation/ExpandedAnimationController.java
+++ b/packages/SystemUI/src/com/android/systemui/bubbles/animation/ExpandedAnimationController.java
@@ -274,16 +274,14 @@
// Then, draw a line across the screen to the bubble's resting position.
path.lineTo(getBubbleLeft(index), expandedY);
} else {
- final float sideMultiplier =
- mLayout.isFirstChildXLeftOfCenter(mCollapsePoint.x) ? -1 : 1;
- final float stackedX = mCollapsePoint.x + (sideMultiplier * index * mStackOffsetPx);
+ final float stackedX = mCollapsePoint.x;
// If we're collapsing, draw a line from the bubble's current position to the side
// of the screen where the bubble will be stacked.
path.lineTo(stackedX, expandedY);
// Then, draw a line down to the stack position.
- path.lineTo(stackedX, mCollapsePoint.y);
+ path.lineTo(stackedX, mCollapsePoint.y + index * mStackOffsetPx);
}
// The lead bubble should be the bubble with the longest distance to travel when we're
diff --git a/packages/SystemUI/src/com/android/systemui/bubbles/animation/StackAnimationController.java b/packages/SystemUI/src/com/android/systemui/bubbles/animation/StackAnimationController.java
index 4c902b9..1205124 100644
--- a/packages/SystemUI/src/com/android/systemui/bubbles/animation/StackAnimationController.java
+++ b/packages/SystemUI/src/com/android/systemui/bubbles/animation/StackAnimationController.java
@@ -744,15 +744,13 @@
@Override
float getOffsetForChainedPropertyAnimation(DynamicAnimation.ViewProperty property) {
- if (property.equals(DynamicAnimation.TRANSLATION_X)) {
+ if (property.equals(DynamicAnimation.TRANSLATION_Y)) {
// If we're in the dismiss target, have the bubbles pile on top of each other with no
// offset.
if (isStackStuckToTarget()) {
return 0f;
} else {
- // Offset to the left if we're on the left, or the right otherwise.
- return mLayout.isFirstChildXLeftOfCenter(mStackPosition.x)
- ? -mStackOffset : mStackOffset;
+ return mStackOffset;
}
} else {
return 0f;
diff --git a/packages/SystemUI/src/com/android/systemui/doze/dagger/DozeScope.java b/packages/SystemUI/src/com/android/systemui/doze/dagger/DozeScope.java
index 7a8b816..435859a 100644
--- a/packages/SystemUI/src/com/android/systemui/doze/dagger/DozeScope.java
+++ b/packages/SystemUI/src/com/android/systemui/doze/dagger/DozeScope.java
@@ -24,7 +24,7 @@
import javax.inject.Scope;
/**
- * Scope annotation for singleton items within the StatusBarComponent.
+ * Scope annotation for singleton items within the DozeComponent.
*/
@Documented
@Retention(RUNTIME)
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/CommandQueue.java b/packages/SystemUI/src/com/android/systemui/statusbar/CommandQueue.java
index 0184fa7..dcee9fa 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/CommandQueue.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/CommandQueue.java
@@ -140,6 +140,8 @@
private static final int MSG_SUPPRESS_AMBIENT_DISPLAY = 56 << MSG_SHIFT;
private static final int MSG_REQUEST_WINDOW_MAGNIFICATION_CONNECTION = 57 << MSG_SHIFT;
private static final int MSG_HANDLE_WINDOW_MANAGER_LOGGING_COMMAND = 58 << MSG_SHIFT;
+ //TODO(b/169175022) Update name and when feature name is locked.
+ private static final int MSG_EMERGENCY_ACTION_LAUNCH_GESTURE = 59 << MSG_SHIFT;
public static final int FLAG_EXCLUDE_NONE = 0;
public static final int FLAG_EXCLUDE_SEARCH_PANEL = 1 << 0;
@@ -258,6 +260,11 @@
default void showAssistDisclosure() { }
default void startAssist(Bundle args) { }
default void onCameraLaunchGestureDetected(int source) { }
+
+ /**
+ * Notifies SysUI that the emergency action gesture was detected.
+ */
+ default void onEmergencyActionLaunchGestureDetected() { }
default void showPictureInPictureMenu() { }
default void setTopAppHidesStatusBar(boolean topAppHidesStatusBar) { }
@@ -730,6 +737,14 @@
}
@Override
+ public void onEmergencyActionLaunchGestureDetected() {
+ synchronized (mLock) {
+ mHandler.removeMessages(MSG_EMERGENCY_ACTION_LAUNCH_GESTURE);
+ mHandler.obtainMessage(MSG_EMERGENCY_ACTION_LAUNCH_GESTURE).sendToTarget();
+ }
+ }
+
+ @Override
public void addQsTile(ComponentName tile) {
synchronized (mLock) {
mHandler.obtainMessage(MSG_ADD_QS_TILE, tile).sendToTarget();
@@ -1186,6 +1201,10 @@
mCallbacks.get(i).onCameraLaunchGestureDetected(msg.arg1);
}
break;
+ case MSG_EMERGENCY_ACTION_LAUNCH_GESTURE:
+ for (int i = 0; i < mCallbacks.size(); i++) {
+ mCallbacks.get(i).onEmergencyActionLaunchGestureDetected();
+ }
case MSG_SHOW_PICTURE_IN_PICTURE_MENU:
for (int i = 0; i < mCallbacks.size(); i++) {
mCallbacks.get(i).showPictureInPictureMenu();
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardClockPositionAlgorithm.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardClockPositionAlgorithm.java
index 1fdf631a..ef4108b 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardClockPositionAlgorithm.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardClockPositionAlgorithm.java
@@ -175,8 +175,8 @@
}
/**
- * Update lock screen mode for testing different layouts
- */
+ * Update lock screen mode for testing different layouts
+ */
public void onLockScreenModeChanged(int mode) {
mLockScreenMode = mode;
}
@@ -241,6 +241,13 @@
clockYDark = MathUtils.lerp(clockYBouncer, clockYDark, shadeExpansion);
float darkAmount = mBypassEnabled && !mHasCustomClock ? 1.0f : mDarkAmount;
+
+ // TODO(b/12836565) - prototyping only adjustment
+ if (mLockScreenMode != KeyguardUpdateMonitor.LOCK_SCREEN_MODE_NORMAL) {
+ // This will keep the clock at the top for AOD
+ darkAmount = 0f;
+ }
+
return (int) (MathUtils.lerp(clockY, clockYDark, darkAmount) + mEmptyDragAmount);
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java
index 873d40f..88a387d 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java
@@ -69,6 +69,7 @@
import android.content.pm.IPackageManager;
import android.content.pm.PackageManager;
import android.content.pm.PackageManager.NameNotFoundException;
+import android.content.pm.ResolveInfo;
import android.content.res.Configuration;
import android.graphics.Point;
import android.graphics.PointF;
@@ -152,6 +153,7 @@
import com.android.systemui.demomode.DemoMode;
import com.android.systemui.demomode.DemoModeCommandReceiver;
import com.android.systemui.demomode.DemoModeController;
+import com.android.systemui.emergency.EmergencyGesture;
import com.android.systemui.fragments.ExtensionFragmentListener;
import com.android.systemui.fragments.FragmentHostManager;
import com.android.systemui.keyguard.DismissCallbackRegistry;
@@ -819,7 +821,7 @@
updateScrimController();
};
-
+ mActivityIntentHelper = new ActivityIntentHelper(mContext);
DateTimeView.setReceiverHandler(timeTickHandler);
}
@@ -833,8 +835,6 @@
mBubblesOptional.get().setExpandListener(mBubbleExpandListener);
}
- mActivityIntentHelper = new ActivityIntentHelper(mContext);
-
mColorExtractor.addOnColorsChangedListener(this);
mStatusBarStateController.addCallback(this,
SysuiStatusBarStateController.RANK_STATUS_BAR);
@@ -3980,6 +3980,27 @@
}
}
+ @Override
+ public void onEmergencyActionLaunchGestureDetected() {
+ // TODO (b/169793384) Polish the panic gesture to be just like its older brother, camera.
+ Intent emergencyIntent = new Intent(EmergencyGesture.ACTION_LAUNCH_EMERGENCY);
+ PackageManager pm = mContext.getPackageManager();
+ ResolveInfo resolveInfo = pm.resolveActivity(emergencyIntent, /*flags=*/0);
+ if (resolveInfo == null) {
+ Log.wtf(TAG, "Couldn't find an app to process the emergency intent.");
+ return;
+ }
+
+ if (mVibrator != null && mVibrator.hasVibrator()) {
+ mVibrator.vibrate(500L);
+ }
+
+ emergencyIntent.setComponent(new ComponentName(resolveInfo.activityInfo.packageName,
+ resolveInfo.activityInfo.name));
+ emergencyIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
+ startActivity(emergencyIntent, /*dismissShade=*/true);
+ }
+
boolean isCameraAllowedByAdmin() {
if (mDevicePolicyManager.getCameraDisabled(null,
mLockscreenUserManager.getCurrentUserId())) {
diff --git a/packages/SystemUI/tests/AndroidManifest.xml b/packages/SystemUI/tests/AndroidManifest.xml
index 2b4ed4e..d541c8f 100644
--- a/packages/SystemUI/tests/AndroidManifest.xml
+++ b/packages/SystemUI/tests/AndroidManifest.xml
@@ -70,6 +70,13 @@
android:exported="false"
android:resizeableActivity="true" />
+ <activity android:name="com.android.systemui.emergency.EmergencyActivityTest"
+ android:exported="true">
+ <intent-filter>
+ <action android:name="com.android.systemui.action.LAUNCH_EMERGENCY"/>
+ </intent-filter>
+ </activity>
+
<activity
android:name="com.android.systemui.globalactions.GlobalActionsImeTest$TestActivity"
android:excludeFromRecents="true"
diff --git a/packages/SystemUI/tests/src/com/android/systemui/accessibility/WindowMagnificationControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/accessibility/WindowMagnificationControllerTest.java
index 5f2fd69..f1606c5 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/accessibility/WindowMagnificationControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/accessibility/WindowMagnificationControllerTest.java
@@ -224,11 +224,12 @@
@Test
- public void onDensityChanged_enabled_updateDimensionsAndLayout() {
+ public void onDensityChanged_enabled_updateDimensionsAndResetWindowMagnification() {
mInstrumentation.runOnMainSync(() -> {
mWindowMagnificationController.enableWindowMagnification(Float.NaN, Float.NaN,
Float.NaN);
Mockito.reset(mWindowManager);
+ Mockito.reset(mMirrorWindowControl);
});
mInstrumentation.runOnMainSync(() -> {
@@ -237,7 +238,9 @@
verify(mResources, atLeastOnce()).getDimensionPixelSize(anyInt());
verify(mWindowManager).removeView(any());
+ verify(mMirrorWindowControl).destroyControl();
verify(mWindowManager).addView(any(), any());
+ verify(mMirrorWindowControl).showControl();
}
@Test
diff --git a/packages/SystemUI/tests/src/com/android/systemui/emergency/EmergencyActivityTest.java b/packages/SystemUI/tests/src/com/android/systemui/emergency/EmergencyActivityTest.java
new file mode 100644
index 0000000..a52a598
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/emergency/EmergencyActivityTest.java
@@ -0,0 +1,34 @@
+/*
+ * 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.
+ */
+
+package com.android.systemui.emergency;
+
+import android.app.Activity;
+import android.os.Bundle;
+
+import com.android.systemui.R;
+
+/**
+ * Test activity for resolving {@link EmergencyGesture#ACTION_LAUNCH_EMERGENCY} action.
+ */
+public class EmergencyActivityTest extends Activity {
+
+ @Override
+ protected void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ setContentView(R.layout.main);
+ }
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarTest.java
index a6ea9966a..d6a7acb 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarTest.java
@@ -24,6 +24,7 @@
import static junit.framework.Assert.assertTrue;
import static junit.framework.TestCase.fail;
+import static org.junit.Assert.assertEquals;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyBoolean;
import static org.mockito.ArgumentMatchers.anyInt;
@@ -34,6 +35,7 @@
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.never;
import static org.mockito.Mockito.reset;
+import static org.mockito.Mockito.spy;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
@@ -43,6 +45,7 @@
import android.app.trust.TrustManager;
import android.content.BroadcastReceiver;
import android.content.ContentResolver;
+import android.content.Intent;
import android.content.IntentFilter;
import android.hardware.display.AmbientDisplayConfiguration;
import android.hardware.fingerprint.FingerprintManager;
@@ -84,6 +87,7 @@
import com.android.systemui.classifier.FalsingManagerFake;
import com.android.systemui.colorextraction.SysuiColorExtractor;
import com.android.systemui.demomode.DemoModeController;
+import com.android.systemui.emergency.EmergencyGesture;
import com.android.systemui.keyguard.DismissCallbackRegistry;
import com.android.systemui.keyguard.KeyguardViewMediator;
import com.android.systemui.keyguard.ScreenLifecycle;
@@ -146,6 +150,7 @@
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
+import org.mockito.ArgumentCaptor;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
@@ -873,6 +878,19 @@
verify(mDozeServiceHost).setDozeSuppressed(false);
}
+ @Test
+ public void onEmergencyActionLaunchGesture_launchesEmergencyIntent() {
+ ArgumentCaptor<Intent> intentCaptor = ArgumentCaptor.forClass(Intent.class);
+ StatusBar statusBarSpy = spy(mStatusBar);
+
+ statusBarSpy.onEmergencyActionLaunchGestureDetected();
+
+ verify(statusBarSpy).startActivity(intentCaptor.capture(), eq(true));
+ Intent sentIntent = intentCaptor.getValue();
+ assertEquals(sentIntent.getAction(), EmergencyGesture.ACTION_LAUNCH_EMERGENCY);
+
+ }
+
public static class TestableNotificationInterruptStateProviderImpl extends
NotificationInterruptStateProviderImpl {
diff --git a/packages/Tethering/tests/unit/src/com/android/networkstack/tethering/PrivateAddressCoordinatorTest.java b/packages/Tethering/tests/unit/src/com/android/networkstack/tethering/PrivateAddressCoordinatorTest.java
index 86e6f11..da13e34 100644
--- a/packages/Tethering/tests/unit/src/com/android/networkstack/tethering/PrivateAddressCoordinatorTest.java
+++ b/packages/Tethering/tests/unit/src/com/android/networkstack/tethering/PrivateAddressCoordinatorTest.java
@@ -194,17 +194,16 @@
@Test
public void testRequestLastDownstreamAddress() throws Exception {
- final int fakeHotspotSubAddr = 0x2b05;
- final IpPrefix predefinedPrefix = new IpPrefix("192.168.43.0/24");
+ final int fakeHotspotSubAddr = 0x2b05; // 43.5
when(mPrivateAddressCoordinator.getRandomInt()).thenReturn(fakeHotspotSubAddr);
final LinkAddress hotspotAddress = mPrivateAddressCoordinator.requestDownstreamAddress(
mHotspotIpServer, true /* useLastAddress */);
- assertEquals("Wrong wifi prefix: ", predefinedPrefix, asIpPrefix(hotspotAddress));
+ assertEquals("Wrong wifi prefix: ", new LinkAddress("192.168.43.5/24"), hotspotAddress);
when(mHotspotIpServer.getAddress()).thenReturn(hotspotAddress);
final LinkAddress usbAddress = mPrivateAddressCoordinator.requestDownstreamAddress(
mUsbIpServer, true /* useLastAddress */);
- assertNotEquals(predefinedPrefix, asIpPrefix(usbAddress));
+ assertEquals("Wrong wifi prefix: ", new LinkAddress("192.168.45.5/24"), usbAddress);
mPrivateAddressCoordinator.releaseDownstream(mHotspotIpServer);
mPrivateAddressCoordinator.releaseDownstream(mUsbIpServer);
@@ -218,6 +217,18 @@
final LinkAddress newUsbAddress = mPrivateAddressCoordinator.requestDownstreamAddress(
mUsbIpServer, true /* useLastAddress */);
assertEquals(usbAddress, newUsbAddress);
+
+ // BUG: the code should detect a conflict, but it doesn't.
+ // Regression introduced in r.android.com/168169687.
+ // Ensure conflict notification works when using cached address.
+ when(mHotspotIpServer.getAddress()).thenReturn(newHotspotAddress);
+ when(mUsbIpServer.getAddress()).thenReturn(usbAddress);
+ final UpstreamNetworkState wifiUpstream = buildUpstreamNetworkState(mWifiNetwork,
+ new LinkAddress("192.168.88.23/16"), null,
+ makeNetworkCapabilities(TRANSPORT_WIFI));
+ mPrivateAddressCoordinator.updateUpstreamPrefix(wifiUpstream);
+ verify(mHotspotIpServer, never()).sendMessage(IpServer.CMD_NOTIFY_PREFIX_CONFLICT);
+ verify(mUsbIpServer, never()).sendMessage(IpServer.CMD_NOTIFY_PREFIX_CONFLICT);
}
private UpstreamNetworkState buildUpstreamNetworkState(final Network network,
diff --git a/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java b/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java
index d71b919..e1c4993 100644
--- a/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java
+++ b/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java
@@ -2633,6 +2633,7 @@
}
@Override
+ @SuppressWarnings("AndroidFrameworkPendingIntentMutability")
public PendingIntent getPendingIntentActivity(Context context, int requestCode, Intent intent,
int flags) {
return PendingIntent.getActivity(context, requestCode, intent, flags);
diff --git a/services/accessibility/java/com/android/server/accessibility/gestures/GestureManifold.java b/services/accessibility/java/com/android/server/accessibility/gestures/GestureManifold.java
index a860db3..14af8c6 100644
--- a/services/accessibility/java/com/android/server/accessibility/gestures/GestureManifold.java
+++ b/services/accessibility/java/com/android/server/accessibility/gestures/GestureManifold.java
@@ -19,6 +19,7 @@
import static android.accessibilityservice.AccessibilityService.GESTURE_2_FINGER_DOUBLE_TAP;
import static android.accessibilityservice.AccessibilityService.GESTURE_2_FINGER_DOUBLE_TAP_AND_HOLD;
import static android.accessibilityservice.AccessibilityService.GESTURE_2_FINGER_SINGLE_TAP;
+import static android.accessibilityservice.AccessibilityService.GESTURE_2_FINGER_SINGLE_TAP_AND_HOLD;
import static android.accessibilityservice.AccessibilityService.GESTURE_2_FINGER_SWIPE_DOWN;
import static android.accessibilityservice.AccessibilityService.GESTURE_2_FINGER_SWIPE_LEFT;
import static android.accessibilityservice.AccessibilityService.GESTURE_2_FINGER_SWIPE_RIGHT;
@@ -27,11 +28,13 @@
import static android.accessibilityservice.AccessibilityService.GESTURE_3_FINGER_DOUBLE_TAP;
import static android.accessibilityservice.AccessibilityService.GESTURE_3_FINGER_DOUBLE_TAP_AND_HOLD;
import static android.accessibilityservice.AccessibilityService.GESTURE_3_FINGER_SINGLE_TAP;
+import static android.accessibilityservice.AccessibilityService.GESTURE_3_FINGER_SINGLE_TAP_AND_HOLD;
import static android.accessibilityservice.AccessibilityService.GESTURE_3_FINGER_SWIPE_DOWN;
import static android.accessibilityservice.AccessibilityService.GESTURE_3_FINGER_SWIPE_LEFT;
import static android.accessibilityservice.AccessibilityService.GESTURE_3_FINGER_SWIPE_RIGHT;
import static android.accessibilityservice.AccessibilityService.GESTURE_3_FINGER_SWIPE_UP;
import static android.accessibilityservice.AccessibilityService.GESTURE_3_FINGER_TRIPLE_TAP;
+import static android.accessibilityservice.AccessibilityService.GESTURE_3_FINGER_TRIPLE_TAP_AND_HOLD;
import static android.accessibilityservice.AccessibilityService.GESTURE_4_FINGER_DOUBLE_TAP;
import static android.accessibilityservice.AccessibilityService.GESTURE_4_FINGER_DOUBLE_TAP_AND_HOLD;
import static android.accessibilityservice.AccessibilityService.GESTURE_4_FINGER_SINGLE_TAP;
@@ -140,6 +143,9 @@
mMultiFingerGestures.add(
new MultiFingerMultiTap(mContext, 2, 1, GESTURE_2_FINGER_SINGLE_TAP, this));
mMultiFingerGestures.add(
+ new MultiFingerMultiTapAndHold(
+ mContext, 2, 1, GESTURE_2_FINGER_SINGLE_TAP_AND_HOLD, this));
+ mMultiFingerGestures.add(
new MultiFingerMultiTap(mContext, 2, 2, GESTURE_2_FINGER_DOUBLE_TAP, this));
mMultiFingerGestures.add(
new MultiFingerMultiTapAndHold(
@@ -153,9 +159,17 @@
new MultiFingerMultiTap(mContext, 3, 2, GESTURE_3_FINGER_DOUBLE_TAP, this));
mMultiFingerGestures.add(
new MultiFingerMultiTapAndHold(
+ mContext, 3, 1, GESTURE_3_FINGER_SINGLE_TAP_AND_HOLD, this));
+ mMultiFingerGestures.add(
+ new MultiFingerMultiTapAndHold(
mContext, 3, 2, GESTURE_3_FINGER_DOUBLE_TAP_AND_HOLD, this));
mMultiFingerGestures.add(
new MultiFingerMultiTap(mContext, 3, 3, GESTURE_3_FINGER_TRIPLE_TAP, this));
+ mMultiFingerGestures.add(
+ new MultiFingerMultiTapAndHold(
+ mContext, 3, 3, GESTURE_3_FINGER_TRIPLE_TAP_AND_HOLD, this));
+ mMultiFingerGestures.add(
+ new MultiFingerMultiTap(mContext, 3, 3, GESTURE_3_FINGER_TRIPLE_TAP, this));
// Four-finger taps.
mMultiFingerGestures.add(
new MultiFingerMultiTap(mContext, 4, 1, GESTURE_4_FINGER_SINGLE_TAP, this));
diff --git a/services/accessibility/java/com/android/server/accessibility/gestures/MultiFingerMultiTap.java b/services/accessibility/java/com/android/server/accessibility/gestures/MultiFingerMultiTap.java
index e15c495..46b4628 100644
--- a/services/accessibility/java/com/android/server/accessibility/gestures/MultiFingerMultiTap.java
+++ b/services/accessibility/java/com/android/server/accessibility/gestures/MultiFingerMultiTap.java
@@ -162,6 +162,7 @@
// Accept down only before target number of fingers are down
// or the finger count is not more than target.
if ((currentFingerCount > mTargetFingerCount) || mIsTargetFingerCountReached) {
+ mIsTargetFingerCountReached = false;
cancelGesture(event, rawEvent, policyFlags);
return;
}
diff --git a/services/core/java/com/android/server/GestureLauncherService.java b/services/core/java/com/android/server/GestureLauncherService.java
index b3d4085..95a7a22 100644
--- a/services/core/java/com/android/server/GestureLauncherService.java
+++ b/services/core/java/com/android/server/GestureLauncherService.java
@@ -38,7 +38,6 @@
import android.os.Trace;
import android.os.UserHandle;
import android.provider.Settings;
-import android.telecom.TelecomManager;
import android.util.MutableBoolean;
import android.util.Slog;
import android.view.KeyEvent;
@@ -46,7 +45,6 @@
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.logging.MetricsLogger;
import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
-import com.android.server.LocalServices;
import com.android.server.statusbar.StatusBarManagerInternal;
import com.android.server.wm.WindowManagerInternal;
@@ -529,15 +527,9 @@
"userSetupComplete = %s, performing panic gesture.",
userSetupComplete));
}
- // TODO(b/160006048): Not all devices have telephony. Check system feature first.
- TelecomManager telecomManager = (TelecomManager) mContext.getSystemService(
- Context.TELECOM_SERVICE);
- mContext.startActivity(telecomManager.createLaunchEmergencyDialerIntent(null).addFlags(
- Intent.FLAG_ACTIVITY_NEW_TASK
- | Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS
- | Intent.FLAG_ACTIVITY_SINGLE_TOP).putExtra(
- "com.android.phone.EmergencyDialer.extra.ENTRY_TYPE",
- 2)); // 2 maps to power button, forcing into fast emergency dialer experience.
+ StatusBarManagerInternal service = LocalServices.getService(
+ StatusBarManagerInternal.class);
+ service.onEmergencyActionLaunchGestureDetected();
return true;
} finally {
Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
diff --git a/services/core/java/com/android/server/biometrics/sensors/ClientMonitorCallbackConverter.java b/services/core/java/com/android/server/biometrics/sensors/ClientMonitorCallbackConverter.java
index cb7db92..c87f62f 100644
--- a/services/core/java/com/android/server/biometrics/sensors/ClientMonitorCallbackConverter.java
+++ b/services/core/java/com/android/server/biometrics/sensors/ClientMonitorCallbackConverter.java
@@ -89,7 +89,8 @@
}
}
- void onError(int sensorId, int cookie, int error, int vendorCode) throws RemoteException {
+ public void onError(int sensorId, int cookie, int error, int vendorCode)
+ throws RemoteException {
if (mSensorReceiver != null) {
mSensorReceiver.onError(sensorId, cookie, error, vendorCode);
} else if (mFaceServiceReceiver != null) {
diff --git a/services/core/java/com/android/server/biometrics/sensors/LockoutConsumer.java b/services/core/java/com/android/server/biometrics/sensors/LockoutConsumer.java
new file mode 100644
index 0000000..153bd46
--- /dev/null
+++ b/services/core/java/com/android/server/biometrics/sensors/LockoutConsumer.java
@@ -0,0 +1,25 @@
+/*
+ * 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.
+ */
+
+package com.android.server.biometrics.sensors;
+
+/**
+ * Interface that clients interested/eligible for lockout events should implement.
+ */
+public interface LockoutConsumer {
+ void onLockoutTimed(long durationMillis);
+ void onLockoutPermanent();
+}
diff --git a/services/core/java/com/android/server/biometrics/sensors/face/FaceUserState.java b/services/core/java/com/android/server/biometrics/sensors/face/FaceUserState.java
index 42c7d16..3fdd279 100644
--- a/services/core/java/com/android/server/biometrics/sensors/face/FaceUserState.java
+++ b/services/core/java/com/android/server/biometrics/sensors/face/FaceUserState.java
@@ -17,7 +17,6 @@
package com.android.server.biometrics.sensors.face;
import android.content.Context;
-import android.hardware.biometrics.BiometricAuthenticator;
import android.hardware.face.Face;
import android.util.AtomicFile;
import android.util.Slog;
@@ -41,7 +40,7 @@
* Class managing the set of faces per user across device reboots.
* @hide
*/
-public class FaceUserState extends BiometricUserState {
+public class FaceUserState extends BiometricUserState<Face> {
private static final String TAG = "FaceState";
private static final String FACE_FILE = "settings_face.xml";
@@ -72,19 +71,9 @@
}
@Override
- public void addBiometric(BiometricAuthenticator.Identifier identifier) {
- if (identifier instanceof Face) {
- super.addBiometric(identifier);
- } else {
- Slog.w(TAG, "Attempted to add non-face identifier");
- }
- }
-
- @Override
- protected ArrayList getCopy(ArrayList array) {
- ArrayList<Face> result = new ArrayList<>(array.size());
- for (int i = 0; i < array.size(); i++) {
- Face f = (Face) array.get(i);
+ protected ArrayList<Face> getCopy(ArrayList<Face> array) {
+ final ArrayList<Face> result = new ArrayList<>();
+ for (Face f : array) {
result.add(new Face(f.getName(), f.getBiometricId(), f.getDeviceId()));
}
return result;
diff --git a/services/core/java/com/android/server/biometrics/sensors/face/FaceUtils.java b/services/core/java/com/android/server/biometrics/sensors/face/FaceUtils.java
index 0197028..f47b228 100644
--- a/services/core/java/com/android/server/biometrics/sensors/face/FaceUtils.java
+++ b/services/core/java/com/android/server/biometrics/sensors/face/FaceUtils.java
@@ -30,7 +30,7 @@
/**
* Utility class for dealing with faces and face settings.
*/
-public class FaceUtils implements BiometricUtils {
+public class FaceUtils implements BiometricUtils<Face> {
private static final Object sInstanceLock = new Object();
private static FaceUtils sInstance;
@@ -56,9 +56,8 @@
}
@Override
- public void addBiometricForUser(Context ctx, int userId,
- BiometricAuthenticator.Identifier identifier) {
- getStateForUser(ctx, userId).addBiometric(identifier);
+ public void addBiometricForUser(Context ctx, int userId, Face face) {
+ getStateForUser(ctx, userId).addBiometric(face);
}
@Override
diff --git a/services/core/java/com/android/server/biometrics/sensors/fingerprint/FingerprintService.java b/services/core/java/com/android/server/biometrics/sensors/fingerprint/FingerprintService.java
index 45de538..dc22970 100644
--- a/services/core/java/com/android/server/biometrics/sensors/fingerprint/FingerprintService.java
+++ b/services/core/java/com/android/server/biometrics/sensors/fingerprint/FingerprintService.java
@@ -33,10 +33,9 @@
import android.hardware.biometrics.BiometricsProtoEnums;
import android.hardware.biometrics.IBiometricSensorReceiver;
import android.hardware.biometrics.IBiometricServiceLockoutResetCallback;
+import android.hardware.biometrics.ITestSession;
import android.hardware.biometrics.fingerprint.IFingerprint;
import android.hardware.biometrics.fingerprint.SensorProps;
-import android.hardware.biometrics.ITestService;
-import android.hardware.biometrics.SensorPropertiesInternal;
import android.hardware.fingerprint.Fingerprint;
import android.hardware.fingerprint.FingerprintSensorPropertiesInternal;
import android.hardware.fingerprint.IFingerprintClientActiveCallback;
@@ -53,6 +52,8 @@
import android.os.ServiceManager;
import android.os.UserHandle;
import android.provider.Settings;
+import android.util.ArrayMap;
+import android.util.ArraySet;
import android.util.EventLog;
import android.util.Pair;
import android.util.Slog;
@@ -91,54 +92,52 @@
private final GestureAvailabilityDispatcher mGestureAvailabilityDispatcher;
private final LockPatternUtils mLockPatternUtils;
@NonNull private List<ServiceProvider> mServiceProviders;
- @Nullable private TestService mTestService;
+ @NonNull private final ArrayMap<Integer, TestSession> mTestSessions;
- private final class TestService extends ITestService.Stub {
+ private final class TestSession extends ITestSession.Stub {
+ private final int mSensorId;
- @Override
- public List<SensorPropertiesInternal> getSensorPropertiesInternal(
- String opPackageName) {
- Utils.checkPermission(getContext(), TEST_BIOMETRIC);
- return null;
+ TestSession(int sensorId) {
+ mSensorId = sensorId;
}
@Override
- public void enableTestHal(int sensorId, boolean enableTestHal) {
+ public void enableTestHal(boolean enableTestHal) {
Utils.checkPermission(getContext(), TEST_BIOMETRIC);
}
@Override
- public void enrollStart(int sensorId, int userId) {
+ public void startEnroll(int userId) {
Utils.checkPermission(getContext(), TEST_BIOMETRIC);
}
@Override
- public void enrollFinish(int sensorId, int userId) {
+ public void finishEnroll(int userId) {
Utils.checkPermission(getContext(), TEST_BIOMETRIC);
}
@Override
- public void authenticateSuccess(int sensorId, int userId) {
+ public void acceptAuthentication(int userId) {
Utils.checkPermission(getContext(), TEST_BIOMETRIC);
}
@Override
- public void authenticateReject(int sensorId, int userId) {
+ public void rejectAuthentication(int userId) {
Utils.checkPermission(getContext(), TEST_BIOMETRIC);
}
@Override
- public void notifyAcquired(int sensorId, int userId) {
+ public void notifyAcquired(int userId) {
Utils.checkPermission(getContext(), TEST_BIOMETRIC);
}
@Override
- public void notifyError(int sensorId, int userId) {
+ public void notifyError(int userId) {
Utils.checkPermission(getContext(), TEST_BIOMETRIC);
}
@Override
- public void internalCleanup(int sensorId, int userId) {
+ public void cleanupInternalState(int userId) {
Utils.checkPermission(getContext(), TEST_BIOMETRIC);
}
}
@@ -148,15 +147,17 @@
*/
private final class FingerprintServiceWrapper extends IFingerprintService.Stub {
@Override
- public ITestService getTestService(String opPackageName) {
+ public ITestSession createTestSession(int sensorId, String opPackageName) {
Utils.checkPermission(getContext(), TEST_BIOMETRIC);
- synchronized (this) {
- if (mTestService == null) {
- mTestService = new TestService();
+ final TestSession session;
+ synchronized (mTestSessions) {
+ if (!mTestSessions.containsKey(sensorId)) {
+ mTestSessions.put(sensorId, new TestSession(sensorId));
}
+ session = mTestSessions.get(sensorId);
}
- return mTestService;
+ return session;
}
@Override // Binder call
@@ -620,6 +621,7 @@
mLockoutResetDispatcher = new LockoutResetDispatcher(context);
mLockPatternUtils = new LockPatternUtils(context);
mServiceProviders = new ArrayList<>();
+ mTestSessions = new ArrayMap<>();
initializeAidlHals();
}
diff --git a/services/core/java/com/android/server/biometrics/sensors/fingerprint/FingerprintUserState.java b/services/core/java/com/android/server/biometrics/sensors/fingerprint/FingerprintUserState.java
index 56312bc..f32d28c 100644
--- a/services/core/java/com/android/server/biometrics/sensors/fingerprint/FingerprintUserState.java
+++ b/services/core/java/com/android/server/biometrics/sensors/fingerprint/FingerprintUserState.java
@@ -17,7 +17,6 @@
package com.android.server.biometrics.sensors.fingerprint;
import android.content.Context;
-import android.hardware.biometrics.BiometricAuthenticator;
import android.hardware.fingerprint.Fingerprint;
import android.util.AtomicFile;
import android.util.Slog;
@@ -40,7 +39,7 @@
* Class managing the set of fingerprint per user across device reboots.
* @hide
*/
-public class FingerprintUserState extends BiometricUserState {
+public class FingerprintUserState extends BiometricUserState<Fingerprint> {
private static final String TAG = "FingerprintState";
private static final String FINGERPRINT_FILE = "settings_fingerprint.xml";
@@ -72,19 +71,9 @@
}
@Override
- public void addBiometric(BiometricAuthenticator.Identifier identifier) {
- if (identifier instanceof Fingerprint) {
- super.addBiometric(identifier);
- } else {
- Slog.w(TAG, "Attempted to add non-fingerprint identifier");
- }
- }
-
- @Override
- protected ArrayList getCopy(ArrayList array) {
- ArrayList<Fingerprint> result = new ArrayList<>();
- for (int i = 0; i < array.size(); i++) {
- Fingerprint fp = (Fingerprint) array.get(i);
+ protected ArrayList<Fingerprint> getCopy(ArrayList<Fingerprint> array) {
+ final ArrayList<Fingerprint> result = new ArrayList<>();
+ for (Fingerprint fp : array) {
result.add(new Fingerprint(fp.getName(), fp.getGroupId(), fp.getBiometricId(),
fp.getDeviceId()));
}
diff --git a/services/core/java/com/android/server/biometrics/sensors/fingerprint/FingerprintUtils.java b/services/core/java/com/android/server/biometrics/sensors/fingerprint/FingerprintUtils.java
index f0bfe12..3bf3a5b 100644
--- a/services/core/java/com/android/server/biometrics/sensors/fingerprint/FingerprintUtils.java
+++ b/services/core/java/com/android/server/biometrics/sensors/fingerprint/FingerprintUtils.java
@@ -30,7 +30,7 @@
/**
* Utility class for dealing with fingerprints and fingerprint settings.
*/
-public class FingerprintUtils implements BiometricUtils {
+public class FingerprintUtils implements BiometricUtils<Fingerprint> {
private static final Object sInstanceLock = new Object();
private static FingerprintUtils sInstance;
@@ -56,9 +56,8 @@
}
@Override
- public void addBiometricForUser(Context context, int userId,
- BiometricAuthenticator.Identifier identifier) {
- getStateForUser(context, userId).addBiometric(identifier);
+ public void addBiometricForUser(Context context, int userId, Fingerprint fingerprint) {
+ getStateForUser(context, userId).addBiometric(fingerprint);
}
@Override
diff --git a/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintAuthenticationClient.java b/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintAuthenticationClient.java
new file mode 100644
index 0000000..e923943
--- /dev/null
+++ b/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintAuthenticationClient.java
@@ -0,0 +1,152 @@
+/*
+ * 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.
+ */
+
+package com.android.server.biometrics.sensors.fingerprint.aidl;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.app.TaskStackListener;
+import android.content.Context;
+import android.hardware.biometrics.BiometricAuthenticator;
+import android.hardware.biometrics.BiometricFingerprintConstants;
+import android.hardware.biometrics.BiometricsProtoEnums;
+import android.hardware.biometrics.common.ICancellationSignal;
+import android.hardware.biometrics.fingerprint.ISession;
+import android.hardware.fingerprint.IUdfpsOverlayController;
+import android.os.IBinder;
+import android.os.RemoteException;
+import android.util.Slog;
+
+import com.android.server.biometrics.sensors.AuthenticationClient;
+import com.android.server.biometrics.sensors.ClientMonitorCallbackConverter;
+import com.android.server.biometrics.sensors.LockoutConsumer;
+import com.android.server.biometrics.sensors.LockoutTracker;
+import com.android.server.biometrics.sensors.fingerprint.Udfps;
+import com.android.server.biometrics.sensors.fingerprint.UdfpsHelper;
+
+import java.util.ArrayList;
+
+/**
+ * Fingerprint-specific authentication client supporting the
+ * {@link android.hardware.biometrics.fingerprint.IFingerprint} AIDL interface.
+ */
+public class FingerprintAuthenticationClient extends AuthenticationClient<ISession> implements
+ Udfps, LockoutConsumer {
+ private static final String TAG = "FingerprintAuthenticationClient";
+
+ @NonNull private final LockoutCache mLockoutCache;
+ @Nullable private final IUdfpsOverlayController mUdfpsOverlayController;
+ @Nullable private ICancellationSignal mCancellationSignal;
+
+ public FingerprintAuthenticationClient(@NonNull Context context,
+ @NonNull LazyDaemon<ISession> lazyDaemon, @NonNull IBinder token,
+ @NonNull ClientMonitorCallbackConverter listener, int targetUserId, long operationId,
+ boolean restricted, @NonNull String owner, int cookie, boolean requireConfirmation,
+ int sensorId, boolean isStrongBiometric, int statsClient,
+ @Nullable TaskStackListener taskStackListener, @NonNull LockoutCache lockoutCache,
+ @Nullable IUdfpsOverlayController udfpsOverlayController) {
+ super(context, lazyDaemon, token, listener, targetUserId, operationId, restricted, owner,
+ cookie, requireConfirmation, sensorId, isStrongBiometric,
+ BiometricsProtoEnums.MODALITY_FINGERPRINT, statsClient, taskStackListener,
+ lockoutCache);
+ mLockoutCache = lockoutCache;
+ mUdfpsOverlayController = udfpsOverlayController;
+ }
+
+ @Override
+ public void onAuthenticated(BiometricAuthenticator.Identifier identifier,
+ boolean authenticated, ArrayList<Byte> token) {
+ super.onAuthenticated(identifier, authenticated, token);
+
+ if (authenticated) {
+ UdfpsHelper.hideUdfpsOverlay(getSensorId(), mUdfpsOverlayController);
+ mCallback.onClientFinished(this, true /* success */);
+ }
+ }
+
+ @Override
+ protected void startHalOperation() {
+ UdfpsHelper.showUdfpsOverlay(getSensorId(), mUdfpsOverlayController);
+ try {
+ mCancellationSignal = getFreshDaemon().authenticate(mSequentialId, mOperationId);
+ } catch (RemoteException e) {
+ Slog.e(TAG, "Remote exception", e);
+ onError(BiometricFingerprintConstants.FINGERPRINT_ERROR_HW_UNAVAILABLE,
+ 0 /* vendorCode */);
+ UdfpsHelper.hideUdfpsOverlay(getSensorId(), mUdfpsOverlayController);
+ mCallback.onClientFinished(this, false /* success */);
+ }
+ }
+
+ @Override
+ protected void stopHalOperation() {
+ UdfpsHelper.hideUdfpsOverlay(getSensorId(), mUdfpsOverlayController);
+ try {
+ mCancellationSignal.cancel();
+ } catch (RemoteException e) {
+ Slog.e(TAG, "Remote exception", e);
+ onError(BiometricFingerprintConstants.FINGERPRINT_ERROR_HW_UNAVAILABLE,
+ 0 /* vendorCode */);
+ mCallback.onClientFinished(this, false /* success */);
+ }
+ }
+
+ @Override
+ public void onPointerDown(int x, int y, float minor, float major) {
+ try {
+ getFreshDaemon().onPointerDown(0 /* pointerId */, x, y, minor, major);
+ } catch (RemoteException e) {
+ Slog.e(TAG, "Remote exception", e);
+ }
+ }
+
+ @Override
+ public void onPointerUp() {
+ try {
+ getFreshDaemon().onPointerUp(0 /* pointerId */);
+ } catch (RemoteException e) {
+ Slog.e(TAG, "Remote exception", e);
+ }
+ }
+
+ @Override
+ public void onLockoutTimed(long durationMillis) {
+ mLockoutCache.setLockoutModeForUser(getTargetUserId(), LockoutTracker.LOCKOUT_TIMED);
+ // Lockout metrics are logged as an error code.
+ final int error = BiometricFingerprintConstants.FINGERPRINT_ERROR_LOCKOUT;
+ logOnError(getContext(), error, 0 /* vendorCode */, getTargetUserId());
+
+ try {
+ getListener().onError(getSensorId(), getCookie(), error, 0 /* vendorCode */);
+ } catch (RemoteException e) {
+ Slog.e(TAG, "Remote exception", e);
+ }
+ }
+
+ @Override
+ public void onLockoutPermanent() {
+ mLockoutCache.setLockoutModeForUser(getTargetUserId(), LockoutTracker.LOCKOUT_PERMANENT);
+ // Lockout metrics are logged as an error code.
+ final int error = BiometricFingerprintConstants.FINGERPRINT_ERROR_LOCKOUT_PERMANENT;
+ logOnError(getContext(), error, 0 /* vendorCode */, getTargetUserId());
+
+ try {
+ getListener().onError(getSensorId(), getCookie(), error, 0 /* vendorCode */);
+ } catch (RemoteException e) {
+ Slog.e(TAG, "Remote exception", e);
+ }
+ }
+}
diff --git a/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintEnrollClient.java b/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintEnrollClient.java
index 33f5418..c96bef1 100644
--- a/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintEnrollClient.java
+++ b/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintEnrollClient.java
@@ -21,6 +21,7 @@
import android.content.Context;
import android.hardware.biometrics.BiometricFaceConstants;
import android.hardware.biometrics.BiometricFingerprintConstants;
+import android.hardware.biometrics.BiometricsProtoEnums;
import android.hardware.biometrics.common.ICancellationSignal;
import android.hardware.biometrics.fingerprint.ISession;
import android.hardware.fingerprint.IUdfpsOverlayController;
@@ -48,11 +49,12 @@
public FingerprintEnrollClient(@NonNull Context context,
@NonNull LazyDaemon<ISession> lazyDaemon, @NonNull IBinder token,
@NonNull ClientMonitorCallbackConverter listener, int userId,
- @NonNull byte[] hardwareAuthToken, @NonNull String owner, @NonNull BiometricUtils utils,
- int statsModality, int sensorId,
+ @NonNull byte[] hardwareAuthToken, @NonNull String owner,
+ @NonNull FingerprintUtils utils, int sensorId,
@Nullable IUdfpsOverlayController udfpsOvelayController, int maxTemplatesPerUser) {
super(context, lazyDaemon, token, listener, userId, hardwareAuthToken, owner, utils,
- 0 /* timeoutSec */, statsModality, sensorId, true /* shouldVibrate */);
+ 0 /* timeoutSec */, BiometricsProtoEnums.MODALITY_FINGERPRINT, sensorId,
+ true /* shouldVibrate */);
mUdfpsOverlayController = udfpsOvelayController;
mMaxTemplatesPerUser = maxTemplatesPerUser;
}
@@ -83,7 +85,7 @@
protected void startHalOperation() {
UdfpsHelper.showUdfpsOverlay(getSensorId(), mUdfpsOverlayController);
try {
- getFreshDaemon().enroll(mSequentialId,
+ mCancellationSignal = getFreshDaemon().enroll(mSequentialId,
HardwareAuthTokenUtils.toHardwareAuthToken(mHardwareAuthToken));
} catch (RemoteException e) {
Slog.e(TAG, "Remote exception when requesting enroll", e);
diff --git a/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintProvider.java b/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintProvider.java
index 0b59086..bac83b9 100644
--- a/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintProvider.java
+++ b/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintProvider.java
@@ -19,12 +19,14 @@
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.app.ActivityManager;
+import android.app.ActivityTaskManager;
+import android.app.IActivityTaskManager;
+import android.app.TaskStackListener;
import android.content.Context;
import android.hardware.biometrics.BiometricsProtoEnums;
import android.hardware.biometrics.fingerprint.IFingerprint;
import android.hardware.biometrics.fingerprint.SensorProps;
import android.hardware.fingerprint.Fingerprint;
-import android.hardware.fingerprint.FingerprintManager;
import android.hardware.fingerprint.FingerprintSensorPropertiesInternal;
import android.hardware.fingerprint.IFingerprintServiceReceiver;
import android.hardware.fingerprint.IUdfpsOverlayController;
@@ -37,12 +39,15 @@
import android.util.SparseArray;
import android.view.Surface;
+import com.android.server.biometrics.Utils;
+import com.android.server.biometrics.sensors.AuthenticationClient;
import com.android.server.biometrics.sensors.ClientMonitor;
import com.android.server.biometrics.sensors.ClientMonitorCallbackConverter;
import com.android.server.biometrics.sensors.LockoutResetDispatcher;
import com.android.server.biometrics.sensors.fingerprint.FingerprintUtils;
import com.android.server.biometrics.sensors.fingerprint.GestureAvailabilityDispatcher;
import com.android.server.biometrics.sensors.fingerprint.ServiceProvider;
+import com.android.server.biometrics.sensors.fingerprint.Udfps;
import java.io.FileDescriptor;
import java.io.PrintWriter;
@@ -52,6 +57,7 @@
/**
* Provider for a single instance of the {@link IFingerprint} HAL.
*/
+@SuppressWarnings("deprecation")
public class FingerprintProvider implements IBinder.DeathRecipient, ServiceProvider {
@NonNull private final Context mContext;
@@ -60,9 +66,48 @@
@NonNull private final ClientMonitor.LazyDaemon<IFingerprint> mLazyDaemon;
@NonNull private final Handler mHandler;
@NonNull private final LockoutResetDispatcher mLockoutResetDispatcher;
+ @NonNull private final IActivityTaskManager mActivityTaskManager;
+ @NonNull private final BiometricTaskStackListener mTaskStackListener;
@Nullable private IUdfpsOverlayController mUdfpsOverlayController;
+ private final class BiometricTaskStackListener extends TaskStackListener {
+ @Override
+ public void onTaskStackChanged() {
+ mHandler.post(() -> {
+ for (int i = 0; i < mSensors.size(); i++) {
+ final ClientMonitor<?> client = mSensors.get(i).getScheduler()
+ .getCurrentClient();
+ if (!(client instanceof AuthenticationClient)) {
+ Slog.e(getTag(), "Task stack changed for client: " + client);
+ continue;
+ }
+ if (Utils.isKeyguard(mContext, client.getOwnerString())) {
+ continue; // Keyguard is always allowed
+ }
+
+ try {
+ final List<ActivityManager.RunningTaskInfo> runningTasks =
+ mActivityTaskManager.getTasks(1);
+ if (!runningTasks.isEmpty()) {
+ final String topPackage =
+ runningTasks.get(0).topActivity.getPackageName();
+ if (!topPackage.contentEquals(client.getOwnerString())
+ && !client.isAlreadyDone()) {
+ Slog.e(getTag(), "Stopping background authentication, top: "
+ + topPackage + " currentClient: " + client);
+ mSensors.get(i).getScheduler()
+ .cancelAuthentication(client.getToken());
+ }
+ }
+ } catch (RemoteException e) {
+ Slog.e(getTag(), "Unable to get running tasks", e);
+ }
+ }
+ });
+ }
+ }
+
public FingerprintProvider(@NonNull Context context, @NonNull SensorProps[] props,
@NonNull String halInstanceName, @NonNull LockoutResetDispatcher lockoutResetDispatcher,
@NonNull GestureAvailabilityDispatcher gestureAvailabilityDispatcher) {
@@ -72,6 +117,8 @@
mLazyDaemon = this::getHalInstance;
mHandler = new Handler(Looper.getMainLooper());
mLockoutResetDispatcher = lockoutResetDispatcher;
+ mActivityTaskManager = ActivityTaskManager.getService();
+ mTaskStackListener = new BiometricTaskStackListener();
for (SensorProps prop : props) {
final int sensorId = prop.commonProps.sensorId;
@@ -135,7 +182,7 @@
mSensors.get(sensorId).getScheduler().scheduleClientMonitor(client, callback);
}
- private void scheduleCreateSessionWithoutHandler(@NonNull IFingerprint daemon, int sensorId,
+ private void createNewSessionWithoutHandler(@NonNull IFingerprint daemon, int sensorId,
int userId) throws RemoteException {
// Note that per IFingerprint createSession contract, this method will block until all
// existing operations are canceled/finished. However, also note that this is fine, since
@@ -178,7 +225,7 @@
try {
if (!mSensors.get(sensorId).hasSessionForUser(userId)) {
- scheduleCreateSessionWithoutHandler(daemon, sensorId, userId);
+ createNewSessionWithoutHandler(daemon, sensorId, userId);
}
final FingerprintResetLockoutClient client = new FingerprintResetLockoutClient(
@@ -222,19 +269,15 @@
final IFingerprint daemon = getHalInstance();
if (daemon == null) {
Slog.e(getTag(), "Null daemon during enroll, sensorId: " + sensorId);
-
- try {
- receiver.onError(FingerprintManager.FINGERPRINT_ERROR_HW_UNAVAILABLE,
- 0 /* vendorCode */);
- } catch (RemoteException e) {
- Slog.e(getTag(), "Unable to send HW_UNAVAILABLE", e);
- }
+ // If this happens, we need to send HW_UNAVAILABLE after the scheduler gets to
+ // this operation. We should not send the callback yet, since the scheduler may
+ // be processing something else.
return;
}
try {
if (!mSensors.get(sensorId).hasSessionForUser(userId)) {
- scheduleCreateSessionWithoutHandler(daemon, sensorId, userId);
+ createNewSessionWithoutHandler(daemon, sensorId, userId);
}
final int maxTemplatesPerUser = mSensors.get(sensorId).getSensorProperties()
@@ -242,8 +285,7 @@
final FingerprintEnrollClient client = new FingerprintEnrollClient(mContext,
mSensors.get(sensorId).getLazySession(), token,
new ClientMonitorCallbackConverter(receiver), userId, hardwareAuthToken,
- opPackageName, FingerprintUtils.getInstance(),
- BiometricsProtoEnums.MODALITY_FINGERPRINT, sensorId,
+ opPackageName, FingerprintUtils.getInstance(), sensorId,
mUdfpsOverlayController, maxTemplatesPerUser);
scheduleForSensor(sensorId, client, new ClientMonitor.Callback() {
@Override
@@ -262,7 +304,7 @@
@Override
public void cancelEnrollment(int sensorId, @NonNull IBinder token) {
-
+ mHandler.post(() -> mSensors.get(sensorId).getScheduler().cancelEnrollment(token));
}
@Override
@@ -277,24 +319,74 @@
int userId, int cookie, @NonNull ClientMonitorCallbackConverter callback,
@NonNull String opPackageName, boolean restricted, int statsClient,
boolean isKeyguard) {
+ mHandler.post(() -> {
+ final IFingerprint daemon = getHalInstance();
+ if (daemon == null) {
+ Slog.e(getTag(), "Null daemon during authenticate, sensorId: " + sensorId);
+ // If this happens, we need to send HW_UNAVAILABLE after the scheduler gets to
+ // this operation. We should not send the callback yet, since the scheduler may
+ // be processing something else.
+ return;
+ }
+ try {
+ if (!mSensors.get(sensorId).hasSessionForUser(userId)) {
+ createNewSessionWithoutHandler(daemon, sensorId, userId);
+ }
+
+ final boolean isStrongBiometric = Utils.isStrongBiometric(sensorId);
+ final FingerprintAuthenticationClient client = new FingerprintAuthenticationClient(
+ mContext, mSensors.get(sensorId).getLazySession(), token, callback, userId,
+ operationId, restricted, opPackageName, cookie,
+ false /* requireConfirmation */, sensorId, isStrongBiometric, statsClient,
+ mTaskStackListener, mSensors.get(sensorId).getLockoutCache(),
+ mUdfpsOverlayController);
+ mSensors.get(sensorId).getScheduler().scheduleClientMonitor(client);
+ } catch (RemoteException e) {
+ Slog.e(getTag(), "Remote exception when scheduling authenticate", e);
+ }
+ });
}
@Override
public void startPreparedClient(int sensorId, int cookie) {
-
+ mHandler.post(() -> mSensors.get(sensorId).getScheduler().startPreparedClient(cookie));
}
@Override
public void cancelAuthentication(int sensorId, @NonNull IBinder token) {
-
+ mHandler.post(() -> mSensors.get(sensorId).getScheduler().cancelAuthentication(token));
}
@Override
public void scheduleRemove(int sensorId, @NonNull IBinder token,
@NonNull IFingerprintServiceReceiver receiver, int fingerId, int userId,
@NonNull String opPackageName) {
+ mHandler.post(() -> {
+ final IFingerprint daemon = getHalInstance();
+ if (daemon == null) {
+ Slog.e(getTag(), "Null daemon during remove, sensorId: " + sensorId);
+ // If this happens, we need to send HW_UNAVAILABLE after the scheduler gets to
+ // this operation. We should not send the callback yet, since the scheduler may
+ // be processing something else.
+ return;
+ }
+ try {
+ if (!mSensors.get(sensorId).hasSessionForUser(userId)) {
+ createNewSessionWithoutHandler(daemon, sensorId, userId);
+ }
+
+ final FingerprintRemovalClient client = new FingerprintRemovalClient(mContext,
+ mSensors.get(sensorId).getLazySession(), token,
+ new ClientMonitorCallbackConverter(receiver), fingerId, userId,
+ opPackageName, FingerprintUtils.getInstance(), sensorId,
+ mSensors.get(sensorId).getAuthenticatorIds());
+ mSensors.get(sensorId).getScheduler().scheduleClientMonitor(client);
+ } catch (RemoteException e) {
+ Slog.e(getTag(), "Remote exception when scheduling remove", e);
+ }
+ });
}
@Override
@@ -320,7 +412,7 @@
@Override
public int getLockoutModeForUser(int sensorId, int userId) {
- return 0;
+ return mSensors.get(sensorId).getLockoutCache().getLockoutModeForUser(userId);
}
@Override
@@ -330,12 +422,24 @@
@Override
public void onPointerDown(int sensorId, int x, int y, float minor, float major) {
-
+ final ClientMonitor<?> client = mSensors.get(sensorId).getScheduler().getCurrentClient();
+ if (!(client instanceof Udfps)) {
+ Slog.e(getTag(), "onPointerDown received during client: " + client);
+ return;
+ }
+ final Udfps udfps = (Udfps) client;
+ udfps.onPointerDown(x, y, minor, major);
}
@Override
public void onPointerUp(int sensorId) {
-
+ final ClientMonitor<?> client = mSensors.get(sensorId).getScheduler().getCurrentClient();
+ if (!(client instanceof Udfps)) {
+ Slog.e(getTag(), "onPointerUp received during client: " + client);
+ return;
+ }
+ final Udfps udfps = (Udfps) client;
+ udfps.onPointerUp();
}
@Override
diff --git a/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintRemovalClient.java b/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintRemovalClient.java
new file mode 100644
index 0000000..df063dc
--- /dev/null
+++ b/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintRemovalClient.java
@@ -0,0 +1,59 @@
+/*
+ * 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.
+ */
+
+package com.android.server.biometrics.sensors.fingerprint.aidl;
+
+import android.annotation.NonNull;
+import android.content.Context;
+import android.hardware.biometrics.BiometricsProtoEnums;
+import android.hardware.biometrics.fingerprint.ISession;
+import android.os.IBinder;
+import android.os.RemoteException;
+import android.util.Slog;
+
+import com.android.server.biometrics.sensors.ClientMonitorCallbackConverter;
+import com.android.server.biometrics.sensors.RemovalClient;
+import com.android.server.biometrics.sensors.fingerprint.FingerprintUtils;
+
+import java.util.Map;
+
+/**
+ * Fingerprint-specific removal client supporting the
+ * {@link android.hardware.biometrics.fingerprint.IFingerprint} interface.
+ */
+public class FingerprintRemovalClient extends RemovalClient<ISession> {
+ private static final String TAG = "FingerprintRemovalClient";
+
+ public FingerprintRemovalClient(@NonNull Context context,
+ @NonNull LazyDaemon<ISession> lazyDaemon, @NonNull IBinder token,
+ @NonNull ClientMonitorCallbackConverter listener, int biometricId, int userId,
+ @NonNull String owner, @NonNull FingerprintUtils utils, int sensorId,
+ @NonNull Map<Integer, Long> authenticatorIds) {
+ super(context, lazyDaemon, token, listener, biometricId, userId, owner, utils, sensorId,
+ authenticatorIds, BiometricsProtoEnums.MODALITY_FINGERPRINT);
+ }
+
+ @Override
+ protected void startHalOperation() {
+ try {
+ final int[] ids = new int[] {mBiometricId};
+ getFreshDaemon().removeEnrollments(mSequentialId, ids);
+ } catch (RemoteException e) {
+ Slog.e(TAG, "Remote exception when requesting remove", e);
+ mCallback.onClientFinished(this, false /* success */);
+ }
+ }
+}
diff --git a/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/Sensor.java b/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/Sensor.java
index 2ed695d..b7aa2d5 100644
--- a/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/Sensor.java
+++ b/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/Sensor.java
@@ -37,12 +37,15 @@
import com.android.server.biometrics.sensors.BiometricScheduler;
import com.android.server.biometrics.sensors.ClientMonitor;
import com.android.server.biometrics.sensors.Interruptable;
+import com.android.server.biometrics.sensors.LockoutConsumer;
import com.android.server.biometrics.sensors.fingerprint.FingerprintUtils;
import com.android.server.biometrics.sensors.fingerprint.GestureAvailabilityDispatcher;
import java.util.ArrayList;
import java.util.Arrays;
+import java.util.HashMap;
import java.util.List;
+import java.util.Map;
/**
* Maintains the state of a single sensor within an instance of the
@@ -55,6 +58,7 @@
@NonNull private final FingerprintSensorPropertiesInternal mSensorProperties;
@NonNull private final BiometricScheduler mScheduler;
@NonNull private final LockoutCache mLockoutCache;
+ @NonNull private final Map<Integer, Long> mAuthenticatorIds;
@Nullable private Session mCurrentSession; // TODO: Death recipient
@NonNull private final ClientMonitor.LazyDaemon<ISession> mLazySession;
@@ -84,6 +88,7 @@
mSensorProperties = sensorProperties;
mScheduler = new BiometricScheduler(tag, gestureAvailabilityDispatcher);
mLockoutCache = new LockoutCache();
+ mAuthenticatorIds = new HashMap<>();
mLazySession = () -> mCurrentSession != null ? mCurrentSession.mSession : null;
}
@@ -209,12 +214,32 @@
@Override
public void onLockoutTimed(long durationMillis) {
+ mHandler.post(() -> {
+ final ClientMonitor<?> client = mScheduler.getCurrentClient();
+ if (!(client instanceof LockoutConsumer)) {
+ Slog.e(mTag, "onLockoutTimed for non-lockout consumer: "
+ + Utils.getClientName(client));
+ return;
+ }
+ final LockoutConsumer lockoutConsumer = (LockoutConsumer) client;
+ lockoutConsumer.onLockoutTimed(durationMillis);
+ });
}
@Override
public void onLockoutPermanent() {
+ mHandler.post(() -> {
+ final ClientMonitor<?> client = mScheduler.getCurrentClient();
+ if (!(client instanceof LockoutConsumer)) {
+ Slog.e(mTag, "onLockoutPermanent for non-lockout consumer: "
+ + Utils.getClientName(client));
+ return;
+ }
+ final LockoutConsumer lockoutConsumer = (LockoutConsumer) client;
+ lockoutConsumer.onLockoutPermanent();
+ });
}
@Override
@@ -270,4 +295,8 @@
@NonNull LockoutCache getLockoutCache() {
return mLockoutCache;
}
+
+ @NonNull Map<Integer, Long> getAuthenticatorIds() {
+ return mAuthenticatorIds;
+ }
}
diff --git a/services/core/java/com/android/server/biometrics/sensors/fingerprint/hidl/Fingerprint21.java b/services/core/java/com/android/server/biometrics/sensors/fingerprint/hidl/Fingerprint21.java
index fedcfa5..da68bc8 100644
--- a/services/core/java/com/android/server/biometrics/sensors/fingerprint/hidl/Fingerprint21.java
+++ b/services/core/java/com/android/server/biometrics/sensors/fingerprint/hidl/Fingerprint21.java
@@ -594,16 +594,12 @@
@Override
public void startPreparedClient(int sensorId, int cookie) {
- mHandler.post(() -> {
- mScheduler.startPreparedClient(cookie);
- });
+ mHandler.post(() -> mScheduler.startPreparedClient(cookie));
}
@Override
public void cancelAuthentication(int sensorId, @NonNull IBinder token) {
- mHandler.post(() -> {
- mScheduler.cancelAuthentication(token);
- });
+ mHandler.post(() -> mScheduler.cancelAuthentication(token));
}
@Override
diff --git a/services/core/java/com/android/server/location/LocationProviderManager.java b/services/core/java/com/android/server/location/LocationProviderManager.java
index 5206571..179fb7d 100644
--- a/services/core/java/com/android/server/location/LocationProviderManager.java
+++ b/services/core/java/com/android/server/location/LocationProviderManager.java
@@ -23,15 +23,12 @@
import static android.location.LocationManager.KEY_LOCATION_CHANGED;
import static android.location.LocationManager.KEY_PROVIDER_ENABLED;
import static android.location.LocationManager.PASSIVE_PROVIDER;
-import static android.location.LocationRequest.PASSIVE_INTERVAL;
import static android.os.IPowerManager.LOCATION_MODE_NO_CHANGE;
import static android.os.PowerManager.LOCATION_MODE_ALL_DISABLED_WHEN_SCREEN_OFF;
import static android.os.PowerManager.LOCATION_MODE_FOREGROUND_ONLY;
import static android.os.PowerManager.LOCATION_MODE_GPS_DISABLED_WHEN_SCREEN_OFF;
import static android.os.PowerManager.LOCATION_MODE_THROTTLE_REQUESTS_WHEN_SCREEN_OFF;
-import static com.android.internal.location.ProviderRequest.EMPTY_REQUEST;
-import static com.android.internal.location.ProviderRequest.INTERVAL_DISABLED;
import static com.android.server.location.LocationManagerService.D;
import static com.android.server.location.LocationManagerService.TAG;
import static com.android.server.location.LocationPermissions.PERMISSION_COARSE;
@@ -503,14 +500,7 @@
LocationRequest.Builder builder = new LocationRequest.Builder(baseRequest);
if (mPermissionLevel < PERMISSION_FINE) {
- switch (baseRequest.getQuality()) {
- case LocationRequest.ACCURACY_FINE:
- builder.setQuality(LocationRequest.ACCURACY_BLOCK);
- break;
- case LocationRequest.POWER_HIGH:
- builder.setQuality(LocationRequest.POWER_LOW);
- break;
- }
+ builder.setQuality(LocationRequest.QUALITY_LOW_POWER);
if (baseRequest.getIntervalMillis() < MIN_COARSE_INTERVAL_MS) {
builder.setIntervalMillis(MIN_COARSE_INTERVAL_MS);
}
@@ -1709,7 +1699,7 @@
@Override
protected boolean registerWithService(ProviderRequest request,
Collection<Registration> registrations) {
- return reregisterWithService(EMPTY_REQUEST, request, registrations);
+ return reregisterWithService(ProviderRequest.EMPTY_REQUEST, request, registrations);
}
@GuardedBy("mLock")
@@ -1778,8 +1768,8 @@
Preconditions.checkState(Thread.holdsLock(mLock));
}
- mLocationEventLog.logProviderUpdateRequest(mName, EMPTY_REQUEST);
- mProvider.setRequest(EMPTY_REQUEST);
+ mLocationEventLog.logProviderUpdateRequest(mName, ProviderRequest.EMPTY_REQUEST);
+ mProvider.setRequest(ProviderRequest.EMPTY_REQUEST);
}
@GuardedBy("mLock")
@@ -1839,27 +1829,27 @@
Preconditions.checkState(Thread.holdsLock(mLock));
}
- long intervalMs = INTERVAL_DISABLED;
+ long intervalMs = ProviderRequest.INTERVAL_DISABLED;
+ int quality = LocationRequest.QUALITY_LOW_POWER;
boolean locationSettingsIgnored = false;
boolean lowPower = true;
- ArrayList<LocationRequest> locationRequests = new ArrayList<>(registrations.size());
for (Registration registration : registrations) {
LocationRequest request = registration.getRequest();
// passive requests do not contribute to the provider request
- if (request.getIntervalMillis() == PASSIVE_INTERVAL) {
+ if (request.getIntervalMillis() == LocationRequest.PASSIVE_INTERVAL) {
continue;
}
intervalMs = min(request.getIntervalMillis(), intervalMs);
+ quality = min(request.getQuality(), quality);
locationSettingsIgnored |= request.isLocationSettingsIgnored();
lowPower &= request.isLowPower();
- locationRequests.add(request);
}
- if (intervalMs == INTERVAL_DISABLED) {
- return EMPTY_REQUEST;
+ if (intervalMs == ProviderRequest.INTERVAL_DISABLED) {
+ return ProviderRequest.EMPTY_REQUEST;
}
// calculate who to blame for power in a somewhat arbitrary fashion. we pick a threshold
@@ -1872,7 +1862,7 @@
} catch (ArithmeticException e) {
// check for and handle overflow by setting to one below the passive interval so passive
// requests are automatically skipped
- thresholdIntervalMs = PASSIVE_INTERVAL - 1;
+ thresholdIntervalMs = LocationRequest.PASSIVE_INTERVAL - 1;
}
WorkSource workSource = new WorkSource();
@@ -1884,9 +1874,9 @@
return new ProviderRequest.Builder()
.setIntervalMillis(intervalMs)
+ .setQuality(quality)
.setLocationSettingsIgnored(locationSettingsIgnored)
.setLowPower(lowPower)
- .setLocationRequests(locationRequests)
.setWorkSource(workSource)
.build();
}
diff --git a/services/core/java/com/android/server/location/PassiveLocationProviderManager.java b/services/core/java/com/android/server/location/PassiveLocationProviderManager.java
index fc10d5f..b771861 100644
--- a/services/core/java/com/android/server/location/PassiveLocationProviderManager.java
+++ b/services/core/java/com/android/server/location/PassiveLocationProviderManager.java
@@ -63,15 +63,7 @@
@Override
protected ProviderRequest mergeRegistrations(Collection<Registration> registrations) {
- boolean locationSettingsIgnored = false;
- for (Registration registration : registrations) {
- locationSettingsIgnored |= registration.getRequest().isLocationSettingsIgnored();
- }
-
- return new ProviderRequest.Builder()
- .setIntervalMillis(0)
- .setLocationSettingsIgnored(locationSettingsIgnored)
- .build();
+ return new ProviderRequest.Builder().setIntervalMillis(0).build();
}
@Override
@@ -79,4 +71,9 @@
Collection<Registration> registrations) {
return 0;
}
+
+ @Override
+ protected String getServiceState() {
+ return mProvider.getCurrentRequest().isActive() ? "registered" : "unregistered";
+ }
}
diff --git a/services/core/java/com/android/server/location/gnss/GnssLocationProvider.java b/services/core/java/com/android/server/location/gnss/GnssLocationProvider.java
index e144b40..e25e605 100644
--- a/services/core/java/com/android/server/location/gnss/GnssLocationProvider.java
+++ b/services/core/java/com/android/server/location/gnss/GnssLocationProvider.java
@@ -708,12 +708,12 @@
// For fast GNSS TTFF
provider = LocationManager.NETWORK_PROVIDER;
locationListener = mNetworkLocationListener;
- locationRequest.setQuality(LocationRequest.POWER_LOW);
+ locationRequest.setQuality(LocationRequest.QUALITY_LOW_POWER);
} else {
// For Device-Based Hybrid (E911)
provider = LocationManager.FUSED_PROVIDER;
locationListener = mFusedLocationListener;
- locationRequest.setQuality(LocationRequest.ACCURACY_FINE);
+ locationRequest.setQuality(LocationRequest.QUALITY_HIGH_ACCURACY);
}
// Ignore location settings if in emergency mode. This is only allowed for
diff --git a/services/core/java/com/android/server/notification/NotificationManagerService.java b/services/core/java/com/android/server/notification/NotificationManagerService.java
index 23798c0..03bf74f 100755
--- a/services/core/java/com/android/server/notification/NotificationManagerService.java
+++ b/services/core/java/com/android/server/notification/NotificationManagerService.java
@@ -4769,7 +4769,7 @@
@Override
public List<ComponentName> getEnabledNotificationListeners(int userId) {
- checkCallerIsSystem();
+ checkNotificationListenerAccess();
return mListeners.getAllowedComponents(userId);
}
@@ -4838,7 +4838,7 @@
public void setNotificationListenerAccessGrantedForUser(ComponentName listener, int userId,
boolean granted) {
Objects.requireNonNull(listener);
- checkCallerIsSystemOrShell();
+ checkNotificationListenerAccess();
final long identity = Binder.clearCallingIdentity();
try {
if (mAllowedManagedServicePackages.test(
@@ -5111,6 +5111,14 @@
}
};
+ protected void checkNotificationListenerAccess() {
+ if (!isCallerSystemOrPhone()) {
+ getContext().enforceCallingPermission(
+ permission.MANAGE_NOTIFICATION_LISTENERS,
+ "Caller must hold " + permission.MANAGE_NOTIFICATION_LISTENERS);
+ }
+ }
+
@VisibleForTesting
protected void setNotificationAssistantAccessGrantedForUserInternal(
ComponentName assistant, int baseUserId, boolean granted) {
diff --git a/services/core/java/com/android/server/pm/ApexManager.java b/services/core/java/com/android/server/pm/ApexManager.java
index ad022c7..7992fea 100644
--- a/services/core/java/com/android/server/pm/ApexManager.java
+++ b/services/core/java/com/android/server/pm/ApexManager.java
@@ -777,12 +777,15 @@
void registerApkInApex(AndroidPackage pkg) {
synchronized (mLock) {
for (ActiveApexInfo aai : mActiveApexInfosCache) {
- if (pkg.getBaseApkPath().startsWith(aai.apexDirectory.getAbsolutePath())) {
+ if (pkg.getBaseApkPath().startsWith(
+ aai.apexDirectory.getAbsolutePath() + File.separator)) {
List<String> apks = mApksInApex.get(aai.apexModuleName);
if (apks == null) {
apks = Lists.newArrayList();
mApksInApex.put(aai.apexModuleName, apks);
}
+ Slog.i(TAG, "Registering " + pkg.getPackageName() + " as apk-in-apex of "
+ + aai.apexModuleName);
apks.add(pkg.getPackageName());
}
}
diff --git a/services/core/java/com/android/server/pm/IncrementalStates.java b/services/core/java/com/android/server/pm/IncrementalStates.java
index dda5faf..ababb83 100644
--- a/services/core/java/com/android/server/pm/IncrementalStates.java
+++ b/services/core/java/com/android/server/pm/IncrementalStates.java
@@ -376,10 +376,10 @@
case IDataLoaderStatusListener.STREAM_INTEGRITY_ERROR:
// fall through
case IDataLoaderStatusListener.STREAM_SOURCE_ERROR: {
- return PackageManager.UNSTARTABLE_REASON_DATALOADER_TRANSPORT;
+ return PackageManager.UNSTARTABLE_REASON_CONNECTION_ERROR;
}
case IDataLoaderStatusListener.STREAM_STORAGE_ERROR: {
- return PackageManager.UNSTARTABLE_REASON_DATALOADER_STORAGE;
+ return PackageManager.UNSTARTABLE_REASON_INSUFFICIENT_STORAGE;
}
default:
return PackageManager.UNSTARTABLE_REASON_UNKNOWN;
diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java
index 805fbbc..bf6a136 100644
--- a/services/core/java/com/android/server/pm/PackageManagerService.java
+++ b/services/core/java/com/android/server/pm/PackageManagerService.java
@@ -17333,7 +17333,7 @@
Bundle extras = new Bundle();
extras.putInt(Intent.EXTRA_UID, mUid);
extras.putString(Intent.EXTRA_PACKAGE_NAME, mPackageName);
- extras.putInt(Intent.EXTRA_REASON, reason);
+ extras.putInt(Intent.EXTRA_UNSTARTABLE_REASON, reason);
// send broadcast to users with this app installed
sendPackageBroadcast(Intent.ACTION_PACKAGE_UNSTARTABLE, mPackageName,
extras, 0 /*flags*/,
diff --git a/services/core/java/com/android/server/pm/permission/BasePermission.java b/services/core/java/com/android/server/pm/permission/BasePermission.java
index c086017..fedbed2 100644
--- a/services/core/java/com/android/server/pm/permission/BasePermission.java
+++ b/services/core/java/com/android/server/pm/permission/BasePermission.java
@@ -32,6 +32,7 @@
import android.content.pm.PackageManagerInternal;
import android.content.pm.PermissionInfo;
import android.content.pm.parsing.component.ParsedPermission;
+import android.os.Build;
import android.os.UserHandle;
import android.util.Log;
import android.util.Slog;
@@ -445,36 +446,38 @@
return null;
}
- public @Nullable PermissionInfo generatePermissionInfo(@NonNull String groupName, int flags) {
- if (groupName == null) {
- if (perm == null || perm.getGroup() == null) {
- return generatePermissionInfo(protectionLevel, flags);
- }
- } else {
- if (perm != null && groupName.equals(perm.getGroup())) {
- return PackageInfoUtils.generatePermissionInfo(perm, flags);
- }
- }
- return null;
+ @Nullable
+ public String getGroup() {
+ return perm != null ? perm.getGroup() : null;
}
- public @NonNull PermissionInfo generatePermissionInfo(int adjustedProtectionLevel, int flags) {
+ @NonNull
+ public PermissionInfo generatePermissionInfo(int flags) {
+ return generatePermissionInfo(flags, Build.VERSION_CODES.CUR_DEVELOPMENT);
+ }
+
+ @NonNull
+ public PermissionInfo generatePermissionInfo(int flags, int targetSdkVersion) {
PermissionInfo permissionInfo;
if (perm != null) {
- final boolean protectionLevelChanged = protectionLevel != adjustedProtectionLevel;
permissionInfo = PackageInfoUtils.generatePermissionInfo(perm, flags);
- if (protectionLevelChanged) {
- // if we return different protection level, don't use the cached info
- permissionInfo = new PermissionInfo(permissionInfo);
- permissionInfo.protectionLevel = adjustedProtectionLevel;
- }
- return permissionInfo;
+ } else {
+ permissionInfo = new PermissionInfo();
+ permissionInfo.name = name;
+ permissionInfo.packageName = sourcePackageName;
+ permissionInfo.nonLocalizedLabel = name;
}
- permissionInfo = new PermissionInfo();
- permissionInfo.name = name;
- permissionInfo.packageName = sourcePackageName;
- permissionInfo.nonLocalizedLabel = name;
- permissionInfo.protectionLevel = protectionLevel;
+ if (targetSdkVersion >= Build.VERSION_CODES.O) {
+ permissionInfo.protectionLevel = protectionLevel;
+ } else {
+ final int protection = protectionLevel & PermissionInfo.PROTECTION_MASK_BASE;
+ if (protection == PermissionInfo.PROTECTION_SIGNATURE) {
+ // Signature permission's protection flags are always reported.
+ permissionInfo.protectionLevel = protectionLevel;
+ } else {
+ permissionInfo.protectionLevel = protection;
+ }
+ }
return permissionInfo;
}
diff --git a/services/core/java/com/android/server/pm/permission/PermissionManagerService.java b/services/core/java/com/android/server/pm/permission/PermissionManagerService.java
index 25e1848..45872a8 100644
--- a/services/core/java/com/android/server/pm/permission/PermissionManagerService.java
+++ b/services/core/java/com/android/server/pm/permission/PermissionManagerService.java
@@ -544,24 +544,37 @@
@Override
@Nullable
- public PermissionInfo getPermissionInfo(String permName, String packageName,
+ public PermissionInfo getPermissionInfo(@NonNull String permName, @NonNull String opPackageName,
@PermissionInfoFlags int flags) {
final int callingUid = getCallingUid();
if (mPackageManagerInt.getInstantAppPackageName(callingUid) != null) {
return null;
}
- final AndroidPackage pkg = mPackageManagerInt.getPackage(packageName);
+ final AndroidPackage opPackage = mPackageManagerInt.getPackage(opPackageName);
+ final int targetSdkVersion = getPermissionInfoCallingTargetSdkVersion(opPackage,
+ callingUid);
synchronized (mLock) {
final BasePermission bp = mSettings.getPermissionLocked(permName);
if (bp == null) {
return null;
}
- final int adjustedProtectionLevel = adjustPermissionProtectionFlagsLocked(
- bp.getProtectionLevel(), pkg, callingUid);
- return bp.generatePermissionInfo(adjustedProtectionLevel, flags);
+ return bp.generatePermissionInfo(flags, targetSdkVersion);
}
}
+ private int getPermissionInfoCallingTargetSdkVersion(@Nullable AndroidPackage pkg, int uid) {
+ final int appId = UserHandle.getAppId(uid);
+ if (appId == Process.ROOT_UID || appId == Process.SYSTEM_UID
+ || appId == Process.SHELL_UID) {
+ // System sees all flags.
+ return Build.VERSION_CODES.CUR_DEVELOPMENT;
+ }
+ if (pkg == null) {
+ return Build.VERSION_CODES.CUR_DEVELOPMENT;
+ }
+ return pkg.getTargetSdkVersion();
+ }
+
@Override
@Nullable
public ParceledListSlice<PermissionInfo> queryPermissionsByGroup(String groupName,
@@ -576,9 +589,8 @@
}
final ArrayList<PermissionInfo> out = new ArrayList<PermissionInfo>(10);
for (BasePermission bp : mSettings.mPermissions.values()) {
- final PermissionInfo pi = bp.generatePermissionInfo(groupName, flags);
- if (pi != null) {
- out.add(pi);
+ if (Objects.equals(bp.getGroup(), groupName)) {
+ out.add(bp.generatePermissionInfo(flags));
}
}
return new ParceledListSlice<>(out);
@@ -2235,32 +2247,6 @@
}
}
- private int adjustPermissionProtectionFlagsLocked(int protectionLevel,
- @Nullable AndroidPackage pkg, int uid) {
- // Signature permission flags area always reported
- final int protectionLevelMasked = protectionLevel
- & (PermissionInfo.PROTECTION_NORMAL
- | PermissionInfo.PROTECTION_DANGEROUS
- | PermissionInfo.PROTECTION_SIGNATURE);
- if (protectionLevelMasked == PermissionInfo.PROTECTION_SIGNATURE) {
- return protectionLevel;
- }
- // System sees all flags.
- final int appId = UserHandle.getAppId(uid);
- if (appId == Process.SYSTEM_UID || appId == Process.ROOT_UID
- || appId == Process.SHELL_UID) {
- return protectionLevel;
- }
- if (pkg == null) {
- return protectionLevel;
- }
- if (pkg.getTargetSdkVersion() < Build.VERSION_CODES.O) {
- return protectionLevelMasked;
- }
- // Apps that target O see flags for all protection levels.
- return protectionLevel;
- }
-
/**
* We might auto-grant permissions if any permission of the group is already granted. Hence if
* the group of a granted permission changes we need to revoke it to avoid having permissions of
@@ -4903,8 +4889,7 @@
BasePermission bp = mSettings.mPermissions.valueAt(i);
if (bp.perm != null && bp.perm.getProtection() == protection) {
- matchingPermissions.add(
- PackageInfoUtils.generatePermissionInfo(bp.perm, 0));
+ matchingPermissions.add(bp.generatePermissionInfo(0));
}
}
}
@@ -4925,8 +4910,7 @@
if (bp.perm != null && (bp.perm.getProtectionFlags() & protectionFlags)
== protectionFlags) {
- matchingPermissions.add(
- PackageInfoUtils.generatePermissionInfo(bp.perm, 0));
+ matchingPermissions.add(bp.generatePermissionInfo(0));
}
}
}
diff --git a/services/core/java/com/android/server/stats/pull/StatsPullAtomService.java b/services/core/java/com/android/server/stats/pull/StatsPullAtomService.java
index e0b671f..f43a4ce 100644
--- a/services/core/java/com/android/server/stats/pull/StatsPullAtomService.java
+++ b/services/core/java/com/android/server/stats/pull/StatsPullAtomService.java
@@ -1630,13 +1630,14 @@
if (modemInfo == null) {
return StatsManager.PULL_SKIP;
}
- pulledData.add(FrameworkStatsLog.buildStatsEvent(atomTag, modemInfo.getTimestamp(),
+ pulledData.add(FrameworkStatsLog.buildStatsEvent(atomTag,
+ modemInfo.getTimestampMillis(),
modemInfo.getSleepTimeMillis(), modemInfo.getIdleTimeMillis(),
- modemInfo.getTransmitPowerInfo().get(0).getTimeInMillis(),
- modemInfo.getTransmitPowerInfo().get(1).getTimeInMillis(),
- modemInfo.getTransmitPowerInfo().get(2).getTimeInMillis(),
- modemInfo.getTransmitPowerInfo().get(3).getTimeInMillis(),
- modemInfo.getTransmitPowerInfo().get(4).getTimeInMillis(),
+ modemInfo.getTransmitDurationMillisAtPowerLevel(0),
+ modemInfo.getTransmitDurationMillisAtPowerLevel(1),
+ modemInfo.getTransmitDurationMillisAtPowerLevel(2),
+ modemInfo.getTransmitDurationMillisAtPowerLevel(3),
+ modemInfo.getTransmitDurationMillisAtPowerLevel(4),
modemInfo.getReceiveTimeMillis(),
-1 /*`energy_used` field name deprecated, use -1 to indicate as unused.*/));
} finally {
diff --git a/services/core/java/com/android/server/statusbar/StatusBarManagerInternal.java b/services/core/java/com/android/server/statusbar/StatusBarManagerInternal.java
index e9215f9..ebfffec 100644
--- a/services/core/java/com/android/server/statusbar/StatusBarManagerInternal.java
+++ b/services/core/java/com/android/server/statusbar/StatusBarManagerInternal.java
@@ -86,6 +86,13 @@
void toggleSplitScreen();
void appTransitionFinished(int displayId);
+ /**
+ * Notifies the status bar that a Emergency Action launch gesture has been detected.
+ *
+ * TODO (b/169175022) Update method name and docs when feature name is locked.
+ */
+ void onEmergencyActionLaunchGestureDetected();
+
void toggleRecentApps();
void setCurrentUser(int newUserId);
diff --git a/services/core/java/com/android/server/statusbar/StatusBarManagerService.java b/services/core/java/com/android/server/statusbar/StatusBarManagerService.java
index 6a68dc1..55cb7f3 100644
--- a/services/core/java/com/android/server/statusbar/StatusBarManagerService.java
+++ b/services/core/java/com/android/server/statusbar/StatusBarManagerService.java
@@ -264,6 +264,23 @@
}
}
+ /**
+ * Notifies the status bar that a Emergency Action launch gesture has been detected.
+ *
+ * TODO (b/169175022) Update method name and docs when feature name is locked.
+ */
+ @Override
+ public void onEmergencyActionLaunchGestureDetected() {
+ if (SPEW) Slog.d(TAG, "Launching emergency action");
+ if (mBar != null) {
+ try {
+ mBar.onEmergencyActionLaunchGestureDetected();
+ } catch (RemoteException e) {
+ if (SPEW) Slog.d(TAG, "Failed to launch emergency action");
+ }
+ }
+ }
+
@Override
public void topAppWindowChanged(int displayId, boolean isFullscreen, boolean isImmersive) {
StatusBarManagerService.this.topAppWindowChanged(displayId, isFullscreen, isImmersive);
diff --git a/services/core/java/com/android/server/wm/InputMonitor.java b/services/core/java/com/android/server/wm/InputMonitor.java
index 143b657..470c2b1 100644
--- a/services/core/java/com/android/server/wm/InputMonitor.java
+++ b/services/core/java/com/android/server/wm/InputMonitor.java
@@ -531,7 +531,7 @@
// event. This is used to omit Surfaces from occlusion detection.
populateOverlayInputInfo(mInvalidInputWindow, w.getName(), type, isVisible);
mInputTransaction.setInputWindowInfo(
- w.mWinAnimator.mSurfaceController.getClientViewRootSurface(),
+ w.mWinAnimator.mSurfaceController.mSurfaceControl,
mInvalidInputWindow);
return;
}
@@ -600,8 +600,7 @@
if (w.mWinAnimator.hasSurface()) {
mInputTransaction.setInputWindowInfo(
- w.mWinAnimator.mSurfaceController.getClientViewRootSurface(),
- inputWindowHandle);
+ w.mWinAnimator.mSurfaceController.mSurfaceControl, inputWindowHandle);
}
}
}
diff --git a/services/core/java/com/android/server/wm/Session.java b/services/core/java/com/android/server/wm/Session.java
index 1fdb49f..02230d6 100644
--- a/services/core/java/com/android/server/wm/Session.java
+++ b/services/core/java/com/android/server/wm/Session.java
@@ -204,15 +204,14 @@
int requestedWidth, int requestedHeight, int viewFlags, int flags, long frameNumber,
ClientWindowFrames outFrames, MergedConfiguration mergedConfiguration,
SurfaceControl outSurfaceControl, InsetsState outInsetsState,
- InsetsSourceControl[] outActiveControls, Point outSurfaceSize,
- SurfaceControl outBLASTSurfaceControl) {
+ InsetsSourceControl[] outActiveControls, Point outSurfaceSize) {
if (false) Slog.d(TAG_WM, ">>>>>> ENTERED relayout from "
+ Binder.getCallingPid());
Trace.traceBegin(TRACE_TAG_WINDOW_MANAGER, mRelayoutTag);
int res = mService.relayoutWindow(this, window, attrs,
requestedWidth, requestedHeight, viewFlags, flags, frameNumber,
outFrames, mergedConfiguration, outSurfaceControl, outInsetsState,
- outActiveControls, outSurfaceSize, outBLASTSurfaceControl);
+ outActiveControls, outSurfaceSize);
Trace.traceEnd(TRACE_TAG_WINDOW_MANAGER);
if (false) Slog.d(TAG_WM, "<<<<<< EXITING relayout to "
+ Binder.getCallingPid());
diff --git a/services/core/java/com/android/server/wm/Task.java b/services/core/java/com/android/server/wm/Task.java
index 0077182..a66a2c4 100644
--- a/services/core/java/com/android/server/wm/Task.java
+++ b/services/core/java/com/android/server/wm/Task.java
@@ -4773,9 +4773,11 @@
// If the task is not yet visible when it is added to the task organizer, then we should
// hide it to allow the task organizer to show it when it is properly reparented. We
// skip this for tasks created by the organizer because they can synchronously update
- // the leash before new children are added to the task.
+ // the leash before new children are added to the task. Also skip this if the task
+ // has already been sent to the organizer which can happen before the first draw if
+ // an existing task is reported to the organizer when it first registers.
if (!mAtmService.getTransitionController().isShellTransitionsEnabled()
- && !mCreatedByOrganizer
+ && !mCreatedByOrganizer && !mTaskAppearedSent
&& mTaskOrganizer != null && !prevHasBeenVisible) {
getSyncTransaction().hide(getSurfaceControl());
commitPendingTransaction();
@@ -4827,6 +4829,11 @@
@VisibleForTesting
boolean setTaskOrganizer(ITaskOrganizer organizer) {
+ return setTaskOrganizer(organizer, false /* skipTaskAppeared */);
+ }
+
+ @VisibleForTesting
+ boolean setTaskOrganizer(ITaskOrganizer organizer, boolean skipTaskAppeared) {
if (mTaskOrganizer == organizer) {
return false;
}
@@ -4839,7 +4846,9 @@
sendTaskVanished(prevOrganizer);
if (mTaskOrganizer != null) {
- sendTaskAppeared();
+ if (!skipTaskAppeared) {
+ sendTaskAppeared();
+ }
} else {
// No longer managed by any organizer.
mTaskAppearedSent = false;
@@ -4852,6 +4861,10 @@
return true;
}
+ boolean updateTaskOrganizerState(boolean forceUpdate) {
+ return updateTaskOrganizerState(forceUpdate, false /* skipTaskAppeared */);
+ }
+
/**
* Called when the task state changes (ie. from windowing mode change) an the task organizer
* state should also be updated.
@@ -4859,9 +4872,10 @@
* @param forceUpdate Updates the task organizer to the one currently specified in the task
* org controller for the task's windowing mode, ignoring the cached
* windowing mode checks.
+ * @param skipTaskAppeared Skips calling taskAppeared for the new organizer if it has changed
* @return {@code true} if task organizer changed.
*/
- boolean updateTaskOrganizerState(boolean forceUpdate) {
+ boolean updateTaskOrganizerState(boolean forceUpdate, boolean skipTaskAppeared) {
if (getSurfaceControl() == null) {
// Can't call onTaskAppeared without a surfacecontrol, so defer this until after one
// is created.
@@ -4877,7 +4891,7 @@
if (!forceUpdate && mTaskOrganizer == organizer) {
return false;
}
- return setTaskOrganizer(organizer);
+ return setTaskOrganizer(organizer, skipTaskAppeared);
}
@Override
@@ -5864,7 +5878,11 @@
final TaskDisplayArea taskDisplayArea = getDisplayArea();
// If the top activity is the resumed one, nothing to do.
+ // For devices that are not in fullscreen mode (e.g. freeform windows), it's possible
+ // we still want to proceed if the visibility of other windows have changed (e.g. bringing
+ // a fullscreen window forward to cover another freeform activity.)
if (mResumedActivity == next && next.isState(RESUMED)
+ && taskDisplayArea.getWindowingMode() != WINDOWING_MODE_FREEFORM
&& taskDisplayArea.allResumedActivitiesComplete()) {
// Make sure we have executed any pending transitions, since there
// should be nothing left to do at this point.
diff --git a/services/core/java/com/android/server/wm/TaskOrganizerController.java b/services/core/java/com/android/server/wm/TaskOrganizerController.java
index 8201d10..48550ed0 100644
--- a/services/core/java/com/android/server/wm/TaskOrganizerController.java
+++ b/services/core/java/com/android/server/wm/TaskOrganizerController.java
@@ -32,6 +32,7 @@
import android.app.WindowConfiguration;
import android.content.Intent;
import android.content.pm.ActivityInfo;
+import android.content.pm.ParceledListSlice;
import android.os.Binder;
import android.os.IBinder;
import android.os.RemoteException;
@@ -39,6 +40,7 @@
import android.view.SurfaceControl;
import android.window.ITaskOrganizer;
import android.window.ITaskOrganizerController;
+import android.window.TaskAppearedInfo;
import android.window.WindowContainerToken;
import com.android.internal.annotations.VisibleForTesting;
@@ -76,8 +78,6 @@
WINDOWING_MODE_FREEFORM
};
- private final WindowManagerGlobalLock mGlobalLock;
-
private class DeathRecipient implements IBinder.DeathRecipient {
ITaskOrganizer mTaskOrganizer;
@@ -103,39 +103,38 @@
* transaction before they are presented to the task org.
*/
private class TaskOrganizerCallbacks {
- final WindowManagerService mService;
final ITaskOrganizer mTaskOrganizer;
final Consumer<Runnable> mDeferTaskOrgCallbacksConsumer;
- private final SurfaceControl.Transaction mTransaction;
-
- TaskOrganizerCallbacks(WindowManagerService wm, ITaskOrganizer taskOrg,
+ TaskOrganizerCallbacks(ITaskOrganizer taskOrg,
Consumer<Runnable> deferTaskOrgCallbacksConsumer) {
- mService = wm;
mDeferTaskOrgCallbacksConsumer = deferTaskOrgCallbacksConsumer;
mTaskOrganizer = taskOrg;
- mTransaction = wm.mTransactionFactory.get();
}
IBinder getBinder() {
return mTaskOrganizer.asBinder();
}
+ SurfaceControl prepareLeash(Task task, boolean visible, String reason) {
+ SurfaceControl outSurfaceControl = new SurfaceControl(task.getSurfaceControl(), reason);
+ if (!task.mCreatedByOrganizer && !visible) {
+ // To prevent flashes, we hide the task prior to sending the leash to the
+ // task org if the task has previously hidden (ie. when entering PIP)
+ mTransaction.hide(outSurfaceControl);
+ mTransaction.apply();
+ }
+ return outSurfaceControl;
+ }
+
void onTaskAppeared(Task task) {
ProtoLog.v(WM_DEBUG_WINDOW_ORGANIZER, "Task appeared taskId=%d", task.mTaskId);
final boolean visible = task.isVisible();
final RunningTaskInfo taskInfo = task.getTaskInfo();
mDeferTaskOrgCallbacksConsumer.accept(() -> {
try {
- SurfaceControl outSurfaceControl = new SurfaceControl(task.getSurfaceControl(),
- "TaskOrganizerController.onTaskAppeared");
- if (!task.mCreatedByOrganizer && !visible) {
- // To prevent flashes, we hide the task prior to sending the leash to the
- // task org if the task has previously hidden (ie. when entering PIP)
- mTransaction.hide(outSurfaceControl);
- mTransaction.apply();
- }
- mTaskOrganizer.onTaskAppeared(taskInfo, outSurfaceControl);
+ mTaskOrganizer.onTaskAppeared(taskInfo, prepareLeash(task, visible,
+ "TaskOrganizerController.onTaskAppeared"));
} catch (RemoteException e) {
Slog.e(TAG, "Exception sending onTaskAppeared callback", e);
}
@@ -208,8 +207,7 @@
mDeferTaskOrgCallbacksConsumer != null
? mDeferTaskOrgCallbacksConsumer
: mService.mWindowManager.mAnimator::addAfterPrepareSurfacesRunnable;
- mOrganizer = new TaskOrganizerCallbacks(mService.mWindowManager, organizer,
- deferTaskOrgCallbacksConsumer);
+ mOrganizer = new TaskOrganizerCallbacks(organizer, deferTaskOrgCallbacksConsumer);
mDeathRecipient = new DeathRecipient(organizer);
try {
organizer.asBinder().linkToDeath(mDeathRecipient, 0);
@@ -219,6 +217,18 @@
mUid = uid;
}
+ /**
+ * Register this task with this state, but doesn't trigger the task appeared callback to
+ * the organizer.
+ */
+ SurfaceControl addTaskWithoutCallback(Task t, String reason) {
+ t.mTaskAppearedSent = true;
+ if (!mOrganizedTasks.contains(t)) {
+ mOrganizedTasks.add(t);
+ }
+ return mOrganizer.prepareLeash(t, t.isVisible(), reason);
+ }
+
void addTask(Task t) {
if (t.mTaskAppearedSent) return;
@@ -265,6 +275,9 @@
}
}
+ private final ActivityTaskManagerService mService;
+ private final WindowManagerGlobalLock mGlobalLock;
+
// List of task organizers by priority
private final LinkedList<ITaskOrganizer> mTaskOrganizers = new LinkedList<>();
private final HashMap<IBinder, TaskOrganizerState> mTaskOrganizerStates = new HashMap<>();
@@ -273,8 +286,7 @@
// Set of organized tasks (by taskId) that dispatch back pressed to their organizers
private final HashSet<Integer> mInterceptBackPressedOnRootTasks = new HashSet();
- private final ActivityTaskManagerService mService;
-
+ private SurfaceControl.Transaction mTransaction;
private RunningTaskInfo mTmpTaskInfo;
private Consumer<Runnable> mDeferTaskOrgCallbacksConsumer;
@@ -299,7 +311,7 @@
* Register a TaskOrganizer to manage tasks as they enter the a supported windowing mode.
*/
@Override
- public void registerTaskOrganizer(ITaskOrganizer organizer) {
+ public ParceledListSlice<TaskAppearedInfo> registerTaskOrganizer(ITaskOrganizer organizer) {
enforceStackPermission("registerTaskOrganizer()");
final int uid = Binder.getCallingUid();
final long origId = Binder.clearCallingIdentity();
@@ -307,17 +319,36 @@
synchronized (mGlobalLock) {
ProtoLog.v(WM_DEBUG_WINDOW_ORGANIZER, "Register task organizer=%s uid=%d",
organizer.asBinder(), uid);
+
+ // Defer initializing the transaction since the transaction factory can be set up
+ // by the tests after construction of the controller
+ if (mTransaction == null) {
+ mTransaction = mService.mWindowManager.mTransactionFactory.get();
+ }
+
if (!mTaskOrganizerStates.containsKey(organizer.asBinder())) {
mTaskOrganizers.add(organizer);
mTaskOrganizerStates.put(organizer.asBinder(),
new TaskOrganizerState(organizer, uid));
}
+
+ final ArrayList<TaskAppearedInfo> taskInfos = new ArrayList<>();
+ final TaskOrganizerState state = mTaskOrganizerStates.get(organizer.asBinder());
mService.mRootWindowContainer.forAllTasks((task) -> {
if (ArrayUtils.contains(UNSUPPORTED_WINDOWING_MODES, task.getWindowingMode())) {
return;
}
- task.updateTaskOrganizerState(true /* forceUpdate */);
+
+ boolean returnTask = !task.mCreatedByOrganizer;
+ task.updateTaskOrganizerState(true /* forceUpdate */,
+ returnTask /* skipTaskAppeared */);
+ if (returnTask) {
+ SurfaceControl outSurfaceControl = state.addTaskWithoutCallback(task,
+ "TaskOrganizerController.registerTaskOrganizer");
+ taskInfos.add(new TaskAppearedInfo(task.getTaskInfo(), outSurfaceControl));
+ }
});
+ return new ParceledListSlice<>(taskInfos);
}
} finally {
Binder.restoreCallingIdentity(origId);
diff --git a/services/core/java/com/android/server/wm/TaskSnapshotSurface.java b/services/core/java/com/android/server/wm/TaskSnapshotSurface.java
index 6904740..efa0525 100644
--- a/services/core/java/com/android/server/wm/TaskSnapshotSurface.java
+++ b/services/core/java/com/android/server/wm/TaskSnapshotSurface.java
@@ -122,7 +122,6 @@
//tmp vars for unused relayout params
private static final Point sTmpSurfaceSize = new Point();
- private static final SurfaceControl sTmpSurfaceControl = new SurfaceControl();
private final Window mWindow;
private final Surface mSurface;
@@ -260,7 +259,7 @@
try {
session.relayout(window, layoutParams, -1, -1, View.VISIBLE, 0, -1,
tmpFrames, tmpMergedConfiguration, surfaceControl, mTmpInsetsState,
- mTempControls, sTmpSurfaceSize, sTmpSurfaceControl);
+ mTempControls, sTmpSurfaceSize);
} catch (RemoteException e) {
// Local call.
}
diff --git a/services/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java
index 429cce2..4be118e 100644
--- a/services/core/java/com/android/server/wm/WindowManagerService.java
+++ b/services/core/java/com/android/server/wm/WindowManagerService.java
@@ -2104,8 +2104,7 @@
int requestedWidth, int requestedHeight, int viewVisibility, int flags,
long frameNumber, ClientWindowFrames outFrames, MergedConfiguration mergedConfiguration,
SurfaceControl outSurfaceControl, InsetsState outInsetsState,
- InsetsSourceControl[] outActiveControls, Point outSurfaceSize,
- SurfaceControl outBLASTSurfaceControl) {
+ InsetsSourceControl[] outActiveControls, Point outSurfaceSize) {
Arrays.fill(outActiveControls, null);
int result = 0;
boolean configChanged;
@@ -2280,8 +2279,7 @@
result = win.relayoutVisibleWindow(result, attrChanges);
try {
- result = createSurfaceControl(outSurfaceControl, outBLASTSurfaceControl,
- result, win, winAnimator);
+ result = createSurfaceControl(outSurfaceControl, result, win, winAnimator);
} catch (Exception e) {
displayContent.getInputMonitor().updateInputWindowsLw(true /*force*/);
@@ -2313,7 +2311,6 @@
// surface, let the client use that, but don't create new surface at this point.
Trace.traceBegin(TRACE_TAG_WINDOW_MANAGER, "relayoutWindow: getSurface");
winAnimator.mSurfaceController.getSurfaceControl(outSurfaceControl);
- winAnimator.mSurfaceController.getBLASTSurfaceControl(outBLASTSurfaceControl);
Trace.traceEnd(TRACE_TAG_WINDOW_MANAGER);
} else {
if (DEBUG_VISIBILITY) Slog.i(TAG_WM, "Releasing surface in: " + win);
@@ -2501,8 +2498,7 @@
return focusMayChange;
}
- private int createSurfaceControl(SurfaceControl outSurfaceControl,
- SurfaceControl outBLASTSurfaceControl, int result,
+ private int createSurfaceControl(SurfaceControl outSurfaceControl, int result,
WindowState win, WindowStateAnimator winAnimator) {
if (!win.mHasSurface) {
result |= RELAYOUT_RES_SURFACE_CHANGED;
@@ -2517,7 +2513,6 @@
}
if (surfaceController != null) {
surfaceController.getSurfaceControl(outSurfaceControl);
- surfaceController.getBLASTSurfaceControl(outBLASTSurfaceControl);
ProtoLog.i(WM_SHOW_TRANSACTIONS, "OUT SURFACE %s: copied", outSurfaceControl);
} else {
diff --git a/services/core/java/com/android/server/wm/WindowState.java b/services/core/java/com/android/server/wm/WindowState.java
index 3b79241..25b4828 100644
--- a/services/core/java/com/android/server/wm/WindowState.java
+++ b/services/core/java/com/android/server/wm/WindowState.java
@@ -5770,7 +5770,7 @@
}
SurfaceControl getClientViewRootSurface() {
- return mWinAnimator.getClientViewRootSurface();
+ return mWinAnimator.getSurfaceControl();
}
@Override
diff --git a/services/core/java/com/android/server/wm/WindowStateAnimator.java b/services/core/java/com/android/server/wm/WindowStateAnimator.java
index 6349e6d..972d0d4 100644
--- a/services/core/java/com/android/server/wm/WindowStateAnimator.java
+++ b/services/core/java/com/android/server/wm/WindowStateAnimator.java
@@ -359,8 +359,8 @@
// surface before destroying it.
if (mSurfaceController != null && mPendingDestroySurface != null) {
mPostDrawTransaction.reparentChildren(
- mSurfaceController.getClientViewRootSurface(),
- mPendingDestroySurface.getClientViewRootSurface()).apply();
+ mSurfaceController.mSurfaceControl,
+ mPendingDestroySurface.mSurfaceControl).apply();
}
destroySurfaceLocked();
mSurfaceDestroyDeferred = true;
@@ -371,7 +371,7 @@
// Our SurfaceControl is always at layer 0 within the parent Surface managed by
// window-state. We want this old Surface to stay on top of the new one
// until we do the swap, so we place it at a positive layer.
- t.setLayer(mSurfaceController.getClientViewRootSurface(), PRESERVED_SURFACE_LAYER);
+ t.setLayer(mSurfaceController.mSurfaceControl, PRESERVED_SURFACE_LAYER);
}
mDestroyPreservedSurfaceUponRedraw = true;
mSurfaceDestroyDeferred = true;
@@ -393,8 +393,8 @@
&& !mPendingDestroySurface.mChildrenDetached
&& (mWin.mActivityRecord == null || !mWin.mActivityRecord.isRelaunching())) {
mPostDrawTransaction.reparentChildren(
- mPendingDestroySurface.getClientViewRootSurface(),
- mSurfaceController.getClientViewRootSurface()).apply();
+ mPendingDestroySurface.mSurfaceControl,
+ mSurfaceController.mSurfaceControl).apply();
}
destroyDeferredSurfaceLocked();
@@ -984,8 +984,8 @@
// Instead let the children get removed when the old surface is deleted.
if (!mPendingDestroySurface.mChildrenDetached) {
mPostDrawTransaction.reparentChildren(
- mPendingDestroySurface.getClientViewRootSurface(),
- mSurfaceController.getClientViewRootSurface());
+ mPendingDestroySurface.mSurfaceControl,
+ mSurfaceController.mSurfaceControl);
}
}
@@ -1201,10 +1201,10 @@
mOffsetPositionForStackResize = offsetPositionForStackResize;
}
- SurfaceControl getClientViewRootSurface() {
+ SurfaceControl getSurfaceControl() {
if (!hasSurface()) {
return null;
}
- return mSurfaceController.getClientViewRootSurface();
+ return mSurfaceController.mSurfaceControl;
}
}
diff --git a/services/core/java/com/android/server/wm/WindowSurfaceController.java b/services/core/java/com/android/server/wm/WindowSurfaceController.java
index d2c36e2..feecda7 100644
--- a/services/core/java/com/android/server/wm/WindowSurfaceController.java
+++ b/services/core/java/com/android/server/wm/WindowSurfaceController.java
@@ -50,11 +50,6 @@
SurfaceControl mSurfaceControl;
- /**
- * WM only uses for deferred transactions.
- */
- SurfaceControl mBLASTSurfaceControl;
-
// Should only be set from within setShown().
private boolean mSurfaceShown = false;
private float mSurfaceX = 0;
@@ -112,22 +107,13 @@
final boolean useBLAST = mService.mUseBLAST && ((win.getAttrs().privateFlags &
WindowManager.LayoutParams.PRIVATE_FLAG_USE_BLAST) != 0);
+
if (useBLAST) {
- b.setContainerLayer();
+ b.setBLASTLayer();
}
mSurfaceControl = b.build();
- if (useBLAST) {
- mBLASTSurfaceControl = win.makeSurface()
- .setParent(mSurfaceControl)
- .setName(name + "(BLAST)")
- .setHidden(false)
- .setBLASTLayer()
- .setCallsite("WindowSurfaceController")
- .build();
- }
-
Trace.traceEnd(TRACE_TAG_WINDOW_MANAGER);
}
@@ -172,9 +158,6 @@
} finally {
setShown(false);
mSurfaceControl = null;
- if (mBLASTSurfaceControl != null) {
- mBLASTSurfaceControl.release();
- }
}
}
@@ -369,12 +352,6 @@
outSurfaceControl.copyFrom(mSurfaceControl, "WindowSurfaceController.getSurfaceControl");
}
- void getBLASTSurfaceControl(SurfaceControl outSurfaceControl) {
- if (mBLASTSurfaceControl != null) {
- outSurfaceControl.copyFrom(mBLASTSurfaceControl, "WindowSurfaceController.getBLASTSurfaceControl");
- }
- }
-
boolean getShown() {
return mSurfaceShown;
}
@@ -399,21 +376,6 @@
return mSurfaceH;
}
- /**
- * Returns the Surface which the client-framework ViewRootImpl will be using.
- * This is either the WSA SurfaceControl or it's BLAST child surface.
- * This has too main uses:
- * 1. This is the Surface the client will add children to, we use this to make
- * sure we don't reparent the BLAST surface itself when calling reparentChildren
- * 2. We use this as the barrier Surface for some deferTransaction operations.
- */
- SurfaceControl getClientViewRootSurface() {
- if (mBLASTSurfaceControl != null) {
- return mBLASTSurfaceControl;
- }
- return mSurfaceControl;
- }
-
void dumpDebug(ProtoOutputStream proto, long fieldId) {
final long token = proto.start(fieldId);
proto.write(SHOWN, mSurfaceShown);
diff --git a/services/tests/mockingservicestests/src/com/android/server/location/LocationProviderManagerTest.java b/services/tests/mockingservicestests/src/com/android/server/location/LocationProviderManagerTest.java
index 31ec4a5..3aedd3c 100644
--- a/services/tests/mockingservicestests/src/com/android/server/location/LocationProviderManagerTest.java
+++ b/services/tests/mockingservicestests/src/com/android/server/location/LocationProviderManagerTest.java
@@ -710,7 +710,6 @@
@Test
public void testProviderRequest() {
assertThat(mProvider.getRequest().isActive()).isFalse();
- assertThat(mProvider.getRequest().getLocationRequests()).isEmpty();
ILocationListener listener1 = createMockLocationListener();
LocationRequest request1 = new LocationRequest.Builder(5).setWorkSource(
@@ -718,7 +717,6 @@
mManager.registerLocationRequest(request1, IDENTITY, PERMISSION_FINE, listener1);
assertThat(mProvider.getRequest().isActive()).isTrue();
- assertThat(mProvider.getRequest().getLocationRequests()).containsExactly(request1);
assertThat(mProvider.getRequest().isLocationSettingsIgnored()).isFalse();
assertThat(mProvider.getRequest().getIntervalMillis()).isEqualTo(5);
assertThat(mProvider.getRequest().isLowPower()).isFalse();
@@ -732,8 +730,6 @@
mManager.registerLocationRequest(request2, IDENTITY, PERMISSION_FINE, listener2);
assertThat(mProvider.getRequest().isActive()).isTrue();
- assertThat(mProvider.getRequest().getLocationRequests()).containsExactly(request1,
- request2);
assertThat(mProvider.getRequest().isLocationSettingsIgnored()).isFalse();
assertThat(mProvider.getRequest().getIntervalMillis()).isEqualTo(1);
assertThat(mProvider.getRequest().isLowPower()).isFalse();
@@ -742,7 +738,6 @@
mManager.unregisterLocationRequest(listener1);
assertThat(mProvider.getRequest().isActive()).isTrue();
- assertThat(mProvider.getRequest().getLocationRequests()).containsExactly(request2);
assertThat(mProvider.getRequest().isLocationSettingsIgnored()).isFalse();
assertThat(mProvider.getRequest().getIntervalMillis()).isEqualTo(1);
assertThat(mProvider.getRequest().isLowPower()).isTrue();
@@ -751,7 +746,6 @@
mManager.unregisterLocationRequest(listener2);
assertThat(mProvider.getRequest().isActive()).isFalse();
- assertThat(mProvider.getRequest().getLocationRequests()).isEmpty();
}
@Test
@@ -855,7 +849,6 @@
mInjector.getSettingsHelper().setLocationEnabled(false, IDENTITY.getUserId());
assertThat(mProvider.getRequest().isActive()).isTrue();
- assertThat(mProvider.getRequest().getLocationRequests()).containsExactly(request2);
assertThat(mProvider.getRequest().getIntervalMillis()).isEqualTo(5);
assertThat(mProvider.getRequest().isLocationSettingsIgnored()).isTrue();
}
diff --git a/services/tests/servicestests/src/com/android/server/GestureLauncherServiceTest.java b/services/tests/servicestests/src/com/android/server/GestureLauncherServiceTest.java
index c91bb93..9a2ce3c 100644
--- a/services/tests/servicestests/src/com/android/server/GestureLauncherServiceTest.java
+++ b/services/tests/servicestests/src/com/android/server/GestureLauncherServiceTest.java
@@ -223,6 +223,25 @@
}
@Test
+ public void testInterceptPowerKeyDown_firstPowerDown_panicGestureNotLaunched() {
+ withPanicGestureEnabledSettingValue(true);
+ mGestureLauncherService.updatePanicButtonGestureEnabled();
+
+ long eventTime = INITIAL_EVENT_TIME_MILLIS
+ + GestureLauncherService.POWER_SHORT_TAP_SEQUENCE_MAX_INTERVAL_MS - 1;
+ KeyEvent keyEvent = new KeyEvent(IGNORED_DOWN_TIME, eventTime, IGNORED_ACTION, IGNORED_CODE,
+ IGNORED_REPEAT);
+ boolean interactive = true;
+ MutableBoolean outLaunched = new MutableBoolean(true);
+ boolean intercepted = mGestureLauncherService.interceptPowerKeyDown(keyEvent, interactive,
+ outLaunched);
+
+ assertFalse(intercepted);
+ assertFalse(outLaunched.value);
+ verify(mMetricsLogger).histogram("power_double_tap_interval", (int) eventTime);
+ }
+
+ @Test
public void testInterceptPowerKeyDown_intervalInBoundsCameraPowerGestureOffInteractive() {
withCameraDoubleTapPowerEnableConfigValue(false);
withCameraDoubleTapPowerDisableSettingValue(1);
@@ -405,6 +424,146 @@
}
@Test
+ public void
+ testInterceptPowerKeyDown_fiveInboundPresses_cameraAndPanicEnabled_bothLaunch() {
+ withCameraDoubleTapPowerEnableConfigValue(true);
+ withCameraDoubleTapPowerDisableSettingValue(0);
+ withPanicGestureEnabledSettingValue(true);
+ mGestureLauncherService.updateCameraDoubleTapPowerEnabled();
+ mGestureLauncherService.updatePanicButtonGestureEnabled();
+ withUserSetupCompleteValue(true);
+
+ // First button press does nothing
+ long eventTime = INITIAL_EVENT_TIME_MILLIS;
+ KeyEvent keyEvent = new KeyEvent(IGNORED_DOWN_TIME, eventTime, IGNORED_ACTION, IGNORED_CODE,
+ IGNORED_REPEAT);
+ boolean interactive = true;
+ MutableBoolean outLaunched = new MutableBoolean(true);
+ boolean intercepted = mGestureLauncherService.interceptPowerKeyDown(keyEvent, interactive,
+ outLaunched);
+ assertFalse(intercepted);
+ assertFalse(outLaunched.value);
+
+ final long interval = GestureLauncherService.CAMERA_POWER_DOUBLE_TAP_MAX_TIME_MS - 1;
+
+ // 2nd button triggers camera
+ eventTime += interval;
+ keyEvent = new KeyEvent(IGNORED_DOWN_TIME, eventTime, IGNORED_ACTION, IGNORED_CODE,
+ IGNORED_REPEAT);
+ outLaunched.value = false;
+ intercepted = mGestureLauncherService.interceptPowerKeyDown(keyEvent, interactive,
+ outLaunched);
+ assertTrue(intercepted);
+ assertTrue(outLaunched.value);
+
+ // Camera checks
+ verify(mStatusBarManagerInternal).onCameraLaunchGestureDetected(
+ StatusBarManager.CAMERA_LAUNCH_SOURCE_POWER_DOUBLE_TAP);
+ verify(mMetricsLogger)
+ .action(MetricsEvent.ACTION_DOUBLE_TAP_POWER_CAMERA_GESTURE, (int) interval);
+
+ final ArgumentCaptor<Integer> cameraIntervalCaptor = ArgumentCaptor.forClass(Integer.class);
+ verify(mMetricsLogger, times(2)).histogram(
+ eq("power_double_tap_interval"), cameraIntervalCaptor.capture());
+ List<Integer> cameraIntervals = cameraIntervalCaptor.getAllValues();
+ assertEquals((int) INITIAL_EVENT_TIME_MILLIS, cameraIntervals.get(0).intValue());
+ assertEquals((int) interval, cameraIntervals.get(1).intValue());
+
+ final ArgumentCaptor<Integer> tapCountCaptor = ArgumentCaptor.forClass(Integer.class);
+ verify(mMetricsLogger, times(2)).histogram(
+ eq("power_consecutive_short_tap_count"), tapCountCaptor.capture());
+ List<Integer> tapCounts = tapCountCaptor.getAllValues();
+ assertEquals(1, tapCounts.get(0).intValue());
+ assertEquals(2, tapCounts.get(1).intValue());
+
+ // Continue the button presses for the panic gesture.
+
+ // Presses 3 and 4 should not trigger any gesture
+ for (int i = 0; i < 2; i++) {
+ eventTime += interval;
+ keyEvent = new KeyEvent(IGNORED_DOWN_TIME, eventTime, IGNORED_ACTION, IGNORED_CODE,
+ IGNORED_REPEAT);
+ outLaunched.value = false;
+ intercepted = mGestureLauncherService.interceptPowerKeyDown(keyEvent, interactive,
+ outLaunched);
+ assertFalse(intercepted);
+ assertFalse(outLaunched.value);
+ }
+
+ // Fifth button press should trigger the panic flow
+ eventTime += interval;
+ keyEvent = new KeyEvent(IGNORED_DOWN_TIME, eventTime, IGNORED_ACTION, IGNORED_CODE,
+ IGNORED_REPEAT);
+ outLaunched.value = false;
+ intercepted = mGestureLauncherService.interceptPowerKeyDown(keyEvent, interactive,
+ outLaunched);
+ assertTrue(intercepted);
+ assertTrue(outLaunched.value);
+
+ // TODO (b/169960245) Verify metric event equiv. to ACTION_DOUBLE_TAP_POWER_CAMERA_GESTURE
+ verify(mStatusBarManagerInternal).onEmergencyActionLaunchGestureDetected();
+
+ final ArgumentCaptor<Integer> intervalCaptor = ArgumentCaptor.forClass(Integer.class);
+ verify(mMetricsLogger, times(5)).histogram(
+ eq("power_double_tap_interval"), intervalCaptor.capture());
+ List<Integer> intervals = intervalCaptor.getAllValues();
+ assertEquals((int) INITIAL_EVENT_TIME_MILLIS, intervals.get(0).intValue());
+ assertEquals((int) interval, intervals.get(1).intValue());
+ }
+
+ @Test
+ public void
+ testInterceptPowerKeyDown_fiveInboundPresses_panicGestureEnabled_launchesPanicFlow() {
+ withPanicGestureEnabledSettingValue(true);
+ mGestureLauncherService.updatePanicButtonGestureEnabled();
+ withUserSetupCompleteValue(true);
+
+ // First button press does nothing
+ long eventTime = INITIAL_EVENT_TIME_MILLIS;
+ KeyEvent keyEvent = new KeyEvent(IGNORED_DOWN_TIME, eventTime, IGNORED_ACTION, IGNORED_CODE,
+ IGNORED_REPEAT);
+ boolean interactive = true;
+ MutableBoolean outLaunched = new MutableBoolean(true);
+ boolean intercepted = mGestureLauncherService.interceptPowerKeyDown(keyEvent, interactive,
+ outLaunched);
+ assertFalse(intercepted);
+ assertFalse(outLaunched.value);
+
+ final long interval = GestureLauncherService.CAMERA_POWER_DOUBLE_TAP_MAX_TIME_MS - 1;
+ // 3 more button presses which should not trigger any gesture (camera gesture disabled)
+ for (int i = 0; i < 3; i++) {
+ eventTime += interval;
+ keyEvent = new KeyEvent(IGNORED_DOWN_TIME, eventTime, IGNORED_ACTION, IGNORED_CODE,
+ IGNORED_REPEAT);
+ outLaunched.value = false;
+ intercepted = mGestureLauncherService.interceptPowerKeyDown(keyEvent, interactive,
+ outLaunched);
+ assertFalse(intercepted);
+ assertFalse(outLaunched.value);
+ }
+
+ // Fifth button press should trigger the panic flow
+ eventTime += interval;
+ keyEvent = new KeyEvent(IGNORED_DOWN_TIME, eventTime, IGNORED_ACTION, IGNORED_CODE,
+ IGNORED_REPEAT);
+ outLaunched.value = false;
+ intercepted = mGestureLauncherService.interceptPowerKeyDown(keyEvent, interactive,
+ outLaunched);
+ assertTrue(outLaunched.value);
+ assertTrue(intercepted);
+
+ // TODO (b/169960245) Verify metric event equiv. to ACTION_DOUBLE_TAP_POWER_CAMERA_GESTURE
+ verify(mStatusBarManagerInternal).onEmergencyActionLaunchGestureDetected();
+
+ final ArgumentCaptor<Integer> intervalCaptor = ArgumentCaptor.forClass(Integer.class);
+ verify(mMetricsLogger, times(5)).histogram(
+ eq("power_double_tap_interval"), intervalCaptor.capture());
+ List<Integer> intervals = intervalCaptor.getAllValues();
+ assertEquals((int) INITIAL_EVENT_TIME_MILLIS, intervals.get(0).intValue());
+ assertEquals((int) interval, intervals.get(1).intValue());
+ }
+
+ @Test
public void testInterceptPowerKeyDown_longpress() {
withCameraDoubleTapPowerEnableConfigValue(true);
withCameraDoubleTapPowerDisableSettingValue(0);
diff --git a/services/tests/servicestests/src/com/android/server/pm/IncrementalStatesTest.java b/services/tests/servicestests/src/com/android/server/pm/IncrementalStatesTest.java
index 62e135b..c4c2f68 100644
--- a/services/tests/servicestests/src/com/android/server/pm/IncrementalStatesTest.java
+++ b/services/tests/servicestests/src/com/android/server/pm/IncrementalStatesTest.java
@@ -146,7 +146,7 @@
// Test that package is now unstartable
assertTrue(mUnstartableCalled.block(WAIT_TIMEOUT_MILLIS));
assertFalse(mIncrementalStates.isStartable());
- assertEquals(PackageManager.UNSTARTABLE_REASON_DATALOADER_TRANSPORT,
+ assertEquals(PackageManager.UNSTARTABLE_REASON_CONNECTION_ERROR,
mUnstartableReason.get());
}
@@ -160,7 +160,7 @@
// Test that package is now unstartable
assertTrue(mUnstartableCalled.block(WAIT_TIMEOUT_MILLIS));
assertFalse(mIncrementalStates.isStartable());
- assertEquals(PackageManager.UNSTARTABLE_REASON_DATALOADER_TRANSPORT,
+ assertEquals(PackageManager.UNSTARTABLE_REASON_CONNECTION_ERROR,
mUnstartableReason.get());
}
@@ -181,7 +181,7 @@
// Test that package is now unstartable
assertTrue(mUnstartableCalled.block(WAIT_TIMEOUT_MILLIS));
assertFalse(mIncrementalStates.isStartable());
- assertEquals(PackageManager.UNSTARTABLE_REASON_DATALOADER_STORAGE,
+ assertEquals(PackageManager.UNSTARTABLE_REASON_INSUFFICIENT_STORAGE,
mUnstartableReason.get());
}
@@ -202,7 +202,7 @@
// Test that package is now unstartable
assertTrue(mUnstartableCalled.block(WAIT_TIMEOUT_MILLIS));
assertFalse(mIncrementalStates.isStartable());
- assertEquals(PackageManager.UNSTARTABLE_REASON_DATALOADER_STORAGE,
+ assertEquals(PackageManager.UNSTARTABLE_REASON_INSUFFICIENT_STORAGE,
mUnstartableReason.get());
}
diff --git a/services/tests/wmtests/src/com/android/server/wm/WindowOrganizerTests.java b/services/tests/wmtests/src/com/android/server/wm/WindowOrganizerTests.java
index 45534dd..aac8397 100644
--- a/services/tests/wmtests/src/com/android/server/wm/WindowOrganizerTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/WindowOrganizerTests.java
@@ -54,12 +54,14 @@
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyBoolean;
import static org.mockito.ArgumentMatchers.anyInt;
+import static org.mockito.Mockito.atLeastOnce;
import android.app.ActivityManager;
import android.app.ActivityManager.RunningTaskInfo;
import android.app.ActivityTaskManager.RootTaskInfo;
import android.app.PictureInPictureParams;
import android.content.pm.ActivityInfo;
+import android.content.pm.ParceledListSlice;
import android.content.res.Configuration;
import android.graphics.Rect;
import android.os.Binder;
@@ -72,6 +74,7 @@
import android.view.SurfaceControl;
import android.window.ITaskOrganizer;
import android.window.IWindowContainerTransactionCallback;
+import android.window.TaskAppearedInfo;
import android.window.WindowContainerTransaction;
import androidx.test.filters.SmallTest;
@@ -79,8 +82,10 @@
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
+import org.mockito.ArgumentCaptor;
import java.util.ArrayList;
+import java.util.HashSet;
import java.util.List;
/**
@@ -93,14 +98,27 @@
@Presubmit
@RunWith(WindowTestRunner.class)
public class WindowOrganizerTests extends WindowTestsBase {
- private ITaskOrganizer registerMockOrganizer() {
+
+ private ITaskOrganizer createMockOrganizer() {
final ITaskOrganizer organizer = mock(ITaskOrganizer.class);
when(organizer.asBinder()).thenReturn(new Binder());
-
- mWm.mAtmService.mTaskOrganizerController.registerTaskOrganizer(organizer);
return organizer;
}
+ private ITaskOrganizer registerMockOrganizer(ArrayList<TaskAppearedInfo> existingTasks) {
+ final ITaskOrganizer organizer = createMockOrganizer();
+ ParceledListSlice<TaskAppearedInfo> tasks =
+ mWm.mAtmService.mTaskOrganizerController.registerTaskOrganizer(organizer);
+ if (existingTasks != null) {
+ existingTasks.addAll(tasks.getList());
+ }
+ return organizer;
+ }
+
+ private ITaskOrganizer registerMockOrganizer() {
+ return registerMockOrganizer(null);
+ }
+
Task createTask(Task stack, boolean fakeDraw) {
final Task task = createTaskInStack(stack, 0);
@@ -128,27 +146,21 @@
@Test
public void testAppearVanish() throws RemoteException {
+ final ITaskOrganizer organizer = registerMockOrganizer();
final Task stack = createStack();
final Task task = createTask(stack);
- final ITaskOrganizer organizer = registerMockOrganizer();
- stack.setWindowingMode(WINDOWING_MODE_MULTI_WINDOW);
- stack.setTaskOrganizer(organizer);
verify(organizer).onTaskAppeared(any(RunningTaskInfo.class), any(SurfaceControl.class));
-
stack.removeImmediately();
verify(organizer).onTaskVanished(any());
}
@Test
public void testAppearWaitsForVisibility() throws RemoteException {
+ final ITaskOrganizer organizer = registerMockOrganizer();
final Task stack = createStack();
final Task task = createTask(stack, false);
- final ITaskOrganizer organizer = registerMockOrganizer();
-
- stack.setWindowingMode(WINDOWING_MODE_MULTI_WINDOW);
- stack.setTaskOrganizer(organizer);
verify(organizer, never())
.onTaskAppeared(any(RunningTaskInfo.class), any(SurfaceControl.class));
@@ -163,9 +175,9 @@
@Test
public void testNoVanishedIfNoAppear() throws RemoteException {
+ final ITaskOrganizer organizer = registerMockOrganizer();
final Task stack = createStack();
final Task task = createTask(stack, false /* hasBeenVisible */);
- final ITaskOrganizer organizer = registerMockOrganizer();
// In this test we skip making the Task visible, and verify
// that even though a TaskOrganizer is set remove doesn't emit
@@ -179,28 +191,25 @@
@Test
public void testTaskNoDraw() throws RemoteException {
+ final ITaskOrganizer organizer = registerMockOrganizer();
final Task stack = createStack();
final Task task = createTask(stack, false /* fakeDraw */);
- final ITaskOrganizer organizer = registerMockOrganizer();
- stack.setWindowingMode(WINDOWING_MODE_MULTI_WINDOW);
verify(organizer, never())
.onTaskAppeared(any(RunningTaskInfo.class), any(SurfaceControl.class));
assertTrue(stack.isOrganized());
mWm.mAtmService.mTaskOrganizerController.unregisterTaskOrganizer(organizer);
- verify(organizer, never()).onTaskVanished(any());
+ assertTaskVanished(organizer, false /* expectVanished */, stack);
assertFalse(stack.isOrganized());
}
@Test
public void testClearOrganizer() throws RemoteException {
+ final ITaskOrganizer organizer = registerMockOrganizer();
final Task stack = createStack();
final Task task = createTask(stack);
- final ITaskOrganizer organizer = registerMockOrganizer();
- stack.setWindowingMode(WINDOWING_MODE_MULTI_WINDOW);
- stack.setTaskOrganizer(organizer);
verify(organizer).onTaskAppeared(any(RunningTaskInfo.class), any(SurfaceControl.class));
assertTrue(stack.isOrganized());
@@ -211,16 +220,15 @@
@Test
public void testUnregisterOrganizer() throws RemoteException {
+ final ITaskOrganizer organizer = registerMockOrganizer();
final Task stack = createStack();
final Task task = createTask(stack);
- final ITaskOrganizer organizer = registerMockOrganizer();
- stack.setWindowingMode(WINDOWING_MODE_MULTI_WINDOW);
verify(organizer).onTaskAppeared(any(RunningTaskInfo.class), any(SurfaceControl.class));
assertTrue(stack.isOrganized());
mWm.mAtmService.mTaskOrganizerController.unregisterTaskOrganizer(organizer);
- verify(organizer).onTaskVanished(any());
+ assertTaskVanished(organizer, true /* expectVanished */, stack);
assertFalse(stack.isOrganized());
}
@@ -232,37 +240,47 @@
final Task task2 = createTask(stack2);
final Task stack3 = createStack();
final Task task3 = createTask(stack3);
- final ITaskOrganizer organizer = registerMockOrganizer();
+ final ArrayList<TaskAppearedInfo> existingTasks = new ArrayList<>();
+ final ITaskOrganizer organizer = registerMockOrganizer(existingTasks);
- // verify that tasks are appeared on registration
- verify(organizer, times(3))
- .onTaskAppeared(any(RunningTaskInfo.class), any(SurfaceControl.class));
+ // verify that tasks are returned and taskAppeared is not called
+ assertContainsTasks(existingTasks, stack, stack2, stack3);
+ verify(organizer, times(0)).onTaskAppeared(any(RunningTaskInfo.class),
+ any(SurfaceControl.class));
+ verify(organizer, times(0)).onTaskVanished(any());
assertTrue(stack.isOrganized());
- // Now we replace the registration and1 verify the new organizer receives tasks
- final ITaskOrganizer organizer2 = registerMockOrganizer();
- verify(organizer2, times(3))
- .onTaskAppeared(any(RunningTaskInfo.class), any(SurfaceControl.class));
+ // Now we replace the registration and verify the new organizer receives existing tasks
+ final ArrayList<TaskAppearedInfo> existingTasks2 = new ArrayList<>();
+ final ITaskOrganizer organizer2 = registerMockOrganizer(existingTasks2);
+ assertContainsTasks(existingTasks2, stack, stack2, stack3);
+ verify(organizer2, times(0)).onTaskAppeared(any(RunningTaskInfo.class),
+ any(SurfaceControl.class));
verify(organizer2, times(0)).onTaskVanished(any());
- // One for task
- verify(organizer, times(3)).onTaskVanished(any());
+ // Removed tasks from the original organizer
+ assertTaskVanished(organizer, true /* expectVanished */, stack, stack2, stack3);
assertTrue(stack2.isOrganized());
// Now we unregister the second one, the first one should automatically be reregistered
// so we verify that it's now seeing changes.
mWm.mAtmService.mTaskOrganizerController.unregisterTaskOrganizer(organizer2);
- verify(organizer, times(6))
+ verify(organizer, times(3))
.onTaskAppeared(any(RunningTaskInfo.class), any(SurfaceControl.class));
- verify(organizer2, times(3)).onTaskVanished(any());
+ assertTaskVanished(organizer2, true /* expectVanished */, stack, stack2, stack3);
}
@Test
public void testRegisterTaskOrganizerWithExistingTasks() throws RemoteException {
final Task stack = createStack();
final Task task = createTask(stack);
+ final Task stack2 = createStack();
+ final Task task2 = createTask(stack2);
+ ArrayList<TaskAppearedInfo> existingTasks = new ArrayList<>();
+ final ITaskOrganizer organizer = registerMockOrganizer(existingTasks);
+ assertContainsTasks(existingTasks, stack, stack2);
- final ITaskOrganizer organizer = registerMockOrganizer();
- verify(organizer, times(1))
+ // Verify we don't get onTaskAppeared if we are returned the tasks
+ verify(organizer, never())
.onTaskAppeared(any(RunningTaskInfo.class), any(SurfaceControl.class));
}
@@ -954,9 +972,9 @@
@Test
public void testPreventDuplicateAppear() throws RemoteException {
+ final ITaskOrganizer organizer = registerMockOrganizer();
final Task stack = createStack();
final Task task = createTask(stack, false /* fakeDraw */);
- final ITaskOrganizer organizer = registerMockOrganizer();
stack.setWindowingMode(WINDOWING_MODE_MULTI_WINDOW);
stack.setTaskOrganizer(organizer);
@@ -977,17 +995,14 @@
@Test
public void testInterceptBackPressedOnTaskRoot() throws RemoteException {
+ final ITaskOrganizer organizer = registerMockOrganizer();
final Task stack = createStack();
final Task task = createTask(stack);
final ActivityRecord activity = createActivityRecordInTask(stack.mDisplayContent, task);
final Task stack2 = createStack();
final Task task2 = createTask(stack2);
final ActivityRecord activity2 = createActivityRecordInTask(stack.mDisplayContent, task2);
- final ITaskOrganizer organizer = registerMockOrganizer();
- // Setup the task to be controlled by the MW mode organizer
- stack.setWindowingMode(WINDOWING_MODE_MULTI_WINDOW);
- stack2.setWindowingMode(WINDOWING_MODE_MULTI_WINDOW);
assertTrue(stack.isOrganized());
assertTrue(stack2.isOrganized());
@@ -1014,9 +1029,9 @@
@Test
public void testBLASTCallbackWithMultipleWindows() throws Exception {
+ final ITaskOrganizer organizer = registerMockOrganizer();
final Task stackController = createStack();
final Task task = createTask(stackController);
- final ITaskOrganizer organizer = registerMockOrganizer();
final WindowState w1 = createAppWindow(task, TYPE_APPLICATION, "Enlightened Window 1");
final WindowState w2 = createAppWindow(task, TYPE_APPLICATION, "Enlightened Window 2");
makeWindowVisible(w1);
@@ -1067,4 +1082,37 @@
assertFalse(daTask.isForceHidden());
});
}
+
+ /**
+ * Verifies that task vanished is called for a specific task.
+ */
+ private void assertTaskVanished(ITaskOrganizer organizer, boolean expectVanished, Task... tasks)
+ throws RemoteException {
+ ArgumentCaptor<RunningTaskInfo> arg = ArgumentCaptor.forClass(RunningTaskInfo.class);
+ verify(organizer, atLeastOnce()).onTaskVanished(arg.capture());
+ List<RunningTaskInfo> taskInfos = arg.getAllValues();
+
+ HashSet<Integer> vanishedTaskIds = new HashSet<>();
+ for (int i = 0; i < taskInfos.size(); i++) {
+ vanishedTaskIds.add(taskInfos.get(i).taskId);
+ }
+ HashSet<Integer> taskIds = new HashSet<>();
+ for (int i = 0; i < tasks.length; i++) {
+ taskIds.add(tasks[i].mTaskId);
+ }
+
+ assertTrue(expectVanished
+ ? vanishedTaskIds.containsAll(taskIds)
+ : !vanishedTaskIds.removeAll(taskIds));
+ }
+
+ private void assertContainsTasks(List<TaskAppearedInfo> taskInfos, Task... expectedTasks) {
+ HashSet<Integer> taskIds = new HashSet<>();
+ for (int i = 0; i < taskInfos.size(); i++) {
+ taskIds.add(taskInfos.get(i).getTaskInfo().taskId);
+ }
+ for (int i = 0; i < expectedTasks.length; i++) {
+ assertTrue(taskIds.contains(expectedTasks[i].mTaskId));
+ }
+ }
}
diff --git a/services/usb/java/com/android/server/usb/MtpNotificationManager.java b/services/usb/java/com/android/server/usb/MtpNotificationManager.java
index 462ee19..39f2f29 100644
--- a/services/usb/java/com/android/server/usb/MtpNotificationManager.java
+++ b/services/usb/java/com/android/server/usb/MtpNotificationManager.java
@@ -64,12 +64,13 @@
private final Context mContext;
private final OnOpenInAppListener mListener;
+ private final Receiver mReceiver;
MtpNotificationManager(Context context, OnOpenInAppListener listener) {
mContext = context;
mListener = listener;
- final Receiver receiver = new Receiver();
- context.registerReceiver(receiver, new IntentFilter(ACTION_OPEN_IN_APPS));
+ mReceiver = new Receiver();
+ context.registerReceiver(mReceiver, new IntentFilter(ACTION_OPEN_IN_APPS));
}
void showNotification(UsbDevice device) {
@@ -154,4 +155,8 @@
static interface OnOpenInAppListener {
void onOpenInApp(UsbDevice device);
}
+
+ public void unregister() {
+ mContext.unregisterReceiver(mReceiver);
+ }
}
diff --git a/services/usb/java/com/android/server/usb/UsbProfileGroupSettingsManager.java b/services/usb/java/com/android/server/usb/UsbProfileGroupSettingsManager.java
index d7b6b5d..26ee03c 100644
--- a/services/usb/java/com/android/server/usb/UsbProfileGroupSettingsManager.java
+++ b/services/usb/java/com/android/server/usb/UsbProfileGroupSettingsManager.java
@@ -261,6 +261,15 @@
}
/**
+ * Unregister all broadcast receivers. Must be called explicitly before
+ * object deletion.
+ */
+ public void unregisterReceivers() {
+ mPackageMonitor.unregister();
+ mMtpNotificationManager.unregister();
+ }
+
+ /**
* Remove all defaults and denied packages for a user.
*
* @param userToRemove The user
diff --git a/services/usb/java/com/android/server/usb/UsbSettingsManager.java b/services/usb/java/com/android/server/usb/UsbSettingsManager.java
index 7b677ee..8e53ff4 100644
--- a/services/usb/java/com/android/server/usb/UsbSettingsManager.java
+++ b/services/usb/java/com/android/server/usb/UsbSettingsManager.java
@@ -124,6 +124,7 @@
if (mSettingsByProfileGroup.indexOfKey(userToRemove.getIdentifier()) >= 0) {
// The user to remove is the parent user of the group. The parent is the last user
// that gets removed. All state will be removed with the user
+ mSettingsByProfileGroup.get(userToRemove.getIdentifier()).unregisterReceivers();
mSettingsByProfileGroup.remove(userToRemove.getIdentifier());
} else {
// We cannot find the parent user of the user that is removed, hence try to remove
diff --git a/telephony/api/system-current.txt b/telephony/api/system-current.txt
index 4fb7302..a67273c 100644
--- a/telephony/api/system-current.txt
+++ b/telephony/api/system-current.txt
@@ -227,6 +227,25 @@
field public static final String MBMS_STREAMING_SERVICE_ACTION = "android.telephony.action.EmbmsStreaming";
}
+ public final class ModemActivityInfo implements android.os.Parcelable {
+ method public int describeContents();
+ method @NonNull public android.telephony.ModemActivityInfo getDelta(@NonNull android.telephony.ModemActivityInfo);
+ method public long getIdleTimeMillis();
+ method public static int getNumTxPowerLevels();
+ method public long getReceiveTimeMillis();
+ method public long getSleepTimeMillis();
+ method public long getTimestampMillis();
+ method public long getTransmitDurationMillisAtPowerLevel(int);
+ method @NonNull public android.util.Range<java.lang.Integer> getTransmitPowerRange(int);
+ method public void writeToParcel(@NonNull android.os.Parcel, int);
+ field @NonNull public static final android.os.Parcelable.Creator<android.telephony.ModemActivityInfo> CREATOR;
+ field public static final int TX_POWER_LEVEL_0 = 0; // 0x0
+ field public static final int TX_POWER_LEVEL_1 = 1; // 0x1
+ field public static final int TX_POWER_LEVEL_2 = 2; // 0x2
+ field public static final int TX_POWER_LEVEL_3 = 3; // 0x3
+ field public static final int TX_POWER_LEVEL_4 = 4; // 0x4
+ }
+
public final class NetworkRegistrationInfo implements android.os.Parcelable {
method @Nullable public android.telephony.DataSpecificRegistrationInfo getDataSpecificInfo();
method public int getRegistrationState();
diff --git a/telephony/java/android/telephony/CellSignalStrength.java b/telephony/java/android/telephony/CellSignalStrength.java
index 2e7bde3..e089657 100644
--- a/telephony/java/android/telephony/CellSignalStrength.java
+++ b/telephony/java/android/telephony/CellSignalStrength.java
@@ -17,6 +17,7 @@
package android.telephony;
import android.annotation.IntRange;
+import android.annotation.SystemApi;
import android.os.PersistableBundle;
/**
@@ -155,11 +156,12 @@
/**
* Returns the number of signal strength levels.
- * @return Number of signal strength levels, enforced to be 5
+ * @return Number of signal strength levels, currently defined in the HAL as 5.
*
* @hide
*/
- public static final int getNumSignalStrengthLevels() {
+ @SystemApi(client = SystemApi.Client.MODULE_LIBRARIES)
+ public static int getNumSignalStrengthLevels() {
return NUM_SIGNAL_STRENGTH_BINS;
}
}
diff --git a/telephony/java/android/telephony/ModemActivityInfo.java b/telephony/java/android/telephony/ModemActivityInfo.java
index debb119..881d85c 100644
--- a/telephony/java/android/telephony/ModemActivityInfo.java
+++ b/telephony/java/android/telephony/ModemActivityInfo.java
@@ -16,8 +16,12 @@
package android.telephony;
+import android.annotation.DurationMillisLong;
+import android.annotation.ElapsedRealtimeLong;
import android.annotation.IntDef;
import android.annotation.NonNull;
+import android.annotation.SystemApi;
+import android.annotation.TestApi;
import android.os.Parcel;
import android.os.Parcelable;
import android.os.SystemClock;
@@ -25,46 +29,50 @@
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
-import java.util.ArrayList;
-import java.util.List;
+import java.util.Arrays;
+import java.util.Objects;
/**
- * Reports modem activity information.
+ * Contains information about the modem's activity. May be useful for power stats reporting.
* @hide
*/
+@SystemApi
+@TestApi
public final class ModemActivityInfo implements Parcelable {
+ private static final int TX_POWER_LEVELS = 5;
+
/**
- * Tx(transmit) power level. see power index below
- * <ul>
- * <li> index 0 = tx_power < 0dBm. </li>
- * <li> index 1 = 0dBm < tx_power < 5dBm. </li>
- * <li> index 2 = 5dBm < tx_power < 15dBm. </li>
- * <li> index 3 = 15dBm < tx_power < 20dBm. </li>
- * <li> index 4 = tx_power > 20dBm. </li>
- * </ul>
- */
- public static final int TX_POWER_LEVELS = 5;
- /**
- * Tx(transmit) power level 0: tx_power < 0dBm
+ * Corresponds to transmit power of less than 0dBm.
*/
public static final int TX_POWER_LEVEL_0 = 0;
+
/**
- * Tx(transmit) power level 1: 0dBm < tx_power < 5dBm
+ * Corresponds to transmit power between 0dBm and 5dBm.
*/
public static final int TX_POWER_LEVEL_1 = 1;
+
/**
- * Tx(transmit) power level 2: 5dBm < tx_power < 15dBm
+ * Corresponds to transmit power between 5dBm and 15dBm.
*/
public static final int TX_POWER_LEVEL_2 = 2;
+
/**
- * Tx(transmit) power level 3: 15dBm < tx_power < 20dBm.
+ * Corresponds to transmit power between 15dBm and 20dBm.
*/
public static final int TX_POWER_LEVEL_3 = 3;
+
/**
- * Tx(transmit) power level 4: tx_power > 20dBm
+ * Corresponds to transmit power above 20dBm.
*/
public static final int TX_POWER_LEVEL_4 = 4;
+ /**
+ * The number of transmit power levels. Fixed by HAL definition.
+ */
+ public static int getNumTxPowerLevels() {
+ return TX_POWER_LEVELS;
+ }
+
/** @hide */
@IntDef(prefix = {"TX_POWER_LEVEL_"}, value = {
TX_POWER_LEVEL_0,
@@ -82,34 +90,39 @@
new Range<>(5, 15),
new Range<>(15, 20),
new Range<>(20, Integer.MAX_VALUE)
-
};
private long mTimestamp;
private int mSleepTimeMs;
private int mIdleTimeMs;
- private List<TransmitPower> mTransmitPowerInfo = new ArrayList<>(TX_POWER_LEVELS);
+ private int[] mTxTimeMs;
private int mRxTimeMs;
+ /**
+ * @hide
+ */
+ @TestApi
public ModemActivityInfo(long timestamp, int sleepTimeMs, int idleTimeMs,
@NonNull int[] txTimeMs, int rxTimeMs) {
+ Objects.requireNonNull(txTimeMs);
+ if (txTimeMs.length != TX_POWER_LEVELS) {
+ throw new IllegalArgumentException("txTimeMs must have length == TX_POWER_LEVELS");
+ }
mTimestamp = timestamp;
mSleepTimeMs = sleepTimeMs;
mIdleTimeMs = idleTimeMs;
- populateTransmitPowerRange(txTimeMs);
+ mTxTimeMs = txTimeMs;
mRxTimeMs = rxTimeMs;
}
- /** helper API to populate tx power range for each bucket **/
- private void populateTransmitPowerRange(@NonNull int[] transmitPowerMs) {
- int i = 0;
- for ( ; i < Math.min(transmitPowerMs.length, TX_POWER_LEVELS); i++) {
- mTransmitPowerInfo.add(i, new TransmitPower(TX_POWER_RANGES[i], transmitPowerMs[i]));
- }
- // Make sure that mTransmitPowerInfo is fully initialized.
- for ( ; i < TX_POWER_LEVELS; i++) {
- mTransmitPowerInfo.add(i, new TransmitPower(TX_POWER_RANGES[i], 0));
- }
+ /**
+ * Provided for convenience in manipulation since the API exposes long values but internal
+ * representations are ints.
+ * @hide
+ */
+ public ModemActivityInfo(long timestamp, long sleepTimeMs, long idleTimeMs,
+ @NonNull int[] txTimeMs, long rxTimeMs) {
+ this(timestamp, (int) sleepTimeMs, (int) idleTimeMs, txTimeMs, (int) rxTimeMs);
}
@Override
@@ -118,7 +131,7 @@
+ " mTimestamp=" + mTimestamp
+ " mSleepTimeMs=" + mSleepTimeMs
+ " mIdleTimeMs=" + mIdleTimeMs
- + " mTransmitPowerInfo[]=" + mTransmitPowerInfo.toString()
+ + " mTxTimeMs[]=" + mTxTimeMs
+ " mRxTimeMs=" + mRxTimeMs
+ "}";
}
@@ -129,14 +142,12 @@
public static final @android.annotation.NonNull Parcelable.Creator<ModemActivityInfo> CREATOR =
new Parcelable.Creator<ModemActivityInfo>() {
- public ModemActivityInfo createFromParcel(Parcel in) {
+ public ModemActivityInfo createFromParcel(@NonNull Parcel in) {
long timestamp = in.readLong();
int sleepTimeMs = in.readInt();
int idleTimeMs = in.readInt();
int[] txTimeMs = new int[TX_POWER_LEVELS];
- for (int i = 0; i < TX_POWER_LEVELS; i++) {
- txTimeMs[i] = in.readInt();
- }
+ in.readIntArray(txTimeMs);
int rxTimeMs = in.readInt();
return new ModemActivityInfo(timestamp, sleepTimeMs, idleTimeMs,
txTimeMs, rxTimeMs);
@@ -147,21 +158,25 @@
}
};
- public void writeToParcel(Parcel dest, int flags) {
+ /**
+ * @param dest The Parcel in which the object should be written.
+ * @param flags Additional flags about how the object should be written.
+ */
+ public void writeToParcel(@NonNull Parcel dest, int flags) {
dest.writeLong(mTimestamp);
dest.writeInt(mSleepTimeMs);
dest.writeInt(mIdleTimeMs);
- for (int i = 0; i < TX_POWER_LEVELS; i++) {
- dest.writeInt(mTransmitPowerInfo.get(i).getTimeInMillis());
- }
+ dest.writeIntArray(mTxTimeMs);
dest.writeInt(mRxTimeMs);
}
/**
- * @return milliseconds since boot, including mTimeInMillis spent in sleep.
- * @see SystemClock#elapsedRealtime()
+ * Gets the timestamp at which this modem activity info was recorded.
+ *
+ * @return The timestamp, as returned by {@link SystemClock#elapsedRealtime()}, when this
+ * {@link ModemActivityInfo} was recorded.
*/
- public long getTimestamp() {
+ public @ElapsedRealtimeLong long getTimestampMillis() {
return mTimestamp;
}
@@ -171,35 +186,48 @@
}
/**
- * @return an arrayList of {@link TransmitPower} with each element representing the total time where
- * transmitter is awake time (in ms) for a given power range (in dbm).
+ * Gets the amount of time the modem spent transmitting at a certain power level.
*
- * @see #TX_POWER_LEVELS
+ * @param powerLevel The power level to query.
+ * @return The amount of time, in milliseconds, that the modem spent transmitting at the
+ * given power level.
*/
- @NonNull
- public List<TransmitPower> getTransmitPowerInfo() {
- return mTransmitPowerInfo;
+ public @DurationMillisLong long getTransmitDurationMillisAtPowerLevel(
+ @TxPowerLevel int powerLevel) {
+ return mTxTimeMs[powerLevel];
+ }
+
+ /**
+ * Gets the range of transmit powers corresponding to a certain power level.
+ *
+ * @param powerLevel The power level to query
+ * @return A {@link Range} object representing the range of intensities (in dBm) to which this
+ * power level corresponds.
+ */
+ public @NonNull Range<Integer> getTransmitPowerRange(@TxPowerLevel int powerLevel) {
+ return TX_POWER_RANGES[powerLevel];
}
/** @hide */
public void setTransmitTimeMillis(int[] txTimeMs) {
- populateTransmitPowerRange(txTimeMs);
- }
-
- /** @hide */
- @NonNull
- public int[] getTransmitTimeMillis() {
- int[] transmitTimeMillis = new int[TX_POWER_LEVELS];
- for (int i = 0; i < transmitTimeMillis.length; i++) {
- transmitTimeMillis[i] = mTransmitPowerInfo.get(i).getTimeInMillis();
- }
- return transmitTimeMillis;
+ mTxTimeMs = Arrays.copyOf(txTimeMs, TX_POWER_LEVELS);
}
/**
- * @return total mTimeInMillis (in ms) when modem is in a low power or sleep state.
+ * @return The raw array of transmit power durations
+ * @hide
*/
- public int getSleepTimeMillis() {
+ @NonNull
+ public int[] getTransmitTimeMillis() {
+ return mTxTimeMs;
+ }
+
+ /**
+ * Gets the amount of time (in milliseconds) when the modem is in a low power or sleep state.
+ *
+ * @return Time in milliseconds.
+ */
+ public @DurationMillisLong long getSleepTimeMillis() {
return mSleepTimeMs;
}
@@ -209,10 +237,44 @@
}
/**
- * @return total mTimeInMillis (in ms) when modem is awake but neither the transmitter nor receiver are
- * active.
+ * Provided for convenience, since the API surface needs to return longs but internal
+ * representations are ints.
+ * @hide
*/
- public int getIdleTimeMillis() {
+ public void setSleepTimeMillis(long sleepTimeMillis) {
+ mSleepTimeMs = (int) sleepTimeMillis;
+ }
+
+ /**
+ * Computes the difference between this instance of {@link ModemActivityInfo} and another
+ * instance.
+ *
+ * This method should be used to compute the amount of activity that has happened between two
+ * samples of modem activity taken at separate times. The sample passed in as an argument to
+ * this method should be the one that's taken later in time (and therefore has more activity).
+ * @param other The other instance of {@link ModemActivityInfo} to diff against.
+ * @return An instance of {@link ModemActivityInfo} representing the difference in modem
+ * activity.
+ */
+ public @NonNull ModemActivityInfo getDelta(@NonNull ModemActivityInfo other) {
+ int[] txTimeMs = new int[ModemActivityInfo.TX_POWER_LEVELS];
+ for (int i = 0; i < ModemActivityInfo.TX_POWER_LEVELS; i++) {
+ txTimeMs[i] = other.mTxTimeMs[i] - mTxTimeMs[i];
+ }
+ return new ModemActivityInfo(other.getTimestampMillis(),
+ other.getSleepTimeMillis() - getSleepTimeMillis(),
+ other.getIdleTimeMillis() - getIdleTimeMillis(),
+ txTimeMs,
+ other.getReceiveTimeMillis() - getReceiveTimeMillis());
+ }
+
+ /**
+ * Gets the amount of time (in milliseconds) when the modem is awake but neither transmitting
+ * nor receiving.
+ *
+ * @return Time in milliseconds.
+ */
+ public @DurationMillisLong long getIdleTimeMillis() {
return mIdleTimeMs;
}
@@ -222,9 +284,20 @@
}
/**
- * @return rx(receive) mTimeInMillis in ms.
+ * Provided for convenience, since the API surface needs to return longs but internal
+ * representations are ints.
+ * @hide
*/
- public int getReceiveTimeMillis() {
+ public void setIdleTimeMillis(long idleTimeMillis) {
+ mIdleTimeMs = (int) idleTimeMillis;
+ }
+
+ /**
+ * Gets the amount of time (in milliseconds) when the modem is awake and receiving data.
+ *
+ * @return Time in milliseconds.
+ */
+ public @DurationMillisLong long getReceiveTimeMillis() {
return mRxTimeMs;
}
@@ -234,71 +307,56 @@
}
/**
+ * Provided for convenience, since the API surface needs to return longs but internal
+ * representations are ints.
+ * @hide
+ */
+ public void setReceiveTimeMillis(long receiveTimeMillis) {
+ mRxTimeMs = (int) receiveTimeMillis;
+ }
+
+ /**
* Indicates if the modem has reported valid {@link ModemActivityInfo}.
*
* @return {@code true} if this {@link ModemActivityInfo} record is valid,
* {@code false} otherwise.
+ * TODO: remove usages of this outside Telephony by always returning a valid (or null) result
+ * from telephony.
+ * @hide
*/
+ @TestApi
public boolean isValid() {
- for (TransmitPower powerInfo : getTransmitPowerInfo()) {
- if(powerInfo.getTimeInMillis() < 0) {
- return false;
- }
- }
+ boolean isTxPowerValid = Arrays.stream(mTxTimeMs).allMatch((i) -> i >= 0);
- return ((getIdleTimeMillis() >= 0) && (getSleepTimeMillis() >= 0)
+ return isTxPowerValid && ((getIdleTimeMillis() >= 0) && (getSleepTimeMillis() >= 0)
&& (getReceiveTimeMillis() >= 0) && !isEmpty());
}
private boolean isEmpty() {
- for (TransmitPower txVal : getTransmitPowerInfo()) {
- if(txVal.getTimeInMillis() != 0) {
- return false;
- }
- }
+ boolean isTxPowerEmpty = mTxTimeMs == null || mTxTimeMs.length == 0
+ || Arrays.stream(mTxTimeMs).allMatch((i) -> i == 0);
- return ((getIdleTimeMillis() == 0) && (getSleepTimeMillis() == 0)
+ return isTxPowerEmpty && ((getIdleTimeMillis() == 0) && (getSleepTimeMillis() == 0)
&& (getReceiveTimeMillis() == 0));
}
- /**
- * Transmit power Information, including the power range in dbm and the total time (in ms) where
- * the transmitter is active/awake for this power range.
- * e.g, range: 0dbm(lower) ~ 5dbm(upper)
- * time: 5ms
- */
- public class TransmitPower {
- private int mTimeInMillis;
- private Range<Integer> mPowerRangeInDbm;
- /** @hide */
- public TransmitPower(@NonNull Range<Integer> range, int time) {
- this.mTimeInMillis = time;
- this.mPowerRangeInDbm = range;
- }
- /**
- * @return the total time in ms where the transmitter is active/wake for this power range
- * {@link #getPowerRangeInDbm()}.
- */
- public int getTimeInMillis() {
- return mTimeInMillis;
- }
+ @Override
+ public boolean equals(Object o) {
+ if (this == o) return true;
+ if (o == null || getClass() != o.getClass()) return false;
+ ModemActivityInfo that = (ModemActivityInfo) o;
+ return mTimestamp == that.mTimestamp
+ && mSleepTimeMs == that.mSleepTimeMs
+ && mIdleTimeMs == that.mIdleTimeMs
+ && mRxTimeMs == that.mRxTimeMs
+ && Arrays.equals(mTxTimeMs, that.mTxTimeMs);
+ }
- /**
- * @return the power range in dbm. e.g, range: 0dbm(lower) ~ 5dbm(upper)
- */
- @NonNull
- public Range<Integer> getPowerRangeInDbm() {
- return mPowerRangeInDbm;
- }
-
- @Override
- public String toString() {
- return "TransmitPower{"
- + " mTimeInMillis=" + mTimeInMillis
- + " mPowerRangeInDbm={" + mPowerRangeInDbm.getLower()
- + "," + mPowerRangeInDbm.getUpper()
- + "}}";
- }
+ @Override
+ public int hashCode() {
+ int result = Objects.hash(mTimestamp, mSleepTimeMs, mIdleTimeMs, mRxTimeMs);
+ result = 31 * result + Arrays.hashCode(mTxTimeMs);
+ return result;
}
}
diff --git a/telephony/java/android/telephony/SmsManager.java b/telephony/java/android/telephony/SmsManager.java
index cab6209..d3fca3e 100644
--- a/telephony/java/android/telephony/SmsManager.java
+++ b/telephony/java/android/telephony/SmsManager.java
@@ -2604,13 +2604,12 @@
/**
* Send an MMS message
*
- * <p class="note"><strong>Note:</strong> This method will never trigger an SMS disambiguation
- * dialog. If this method is called on a device that has multiple active subscriptions, this
- * {@link SmsManager} instance has been created with {@link #getDefault()}, and no user-defined
- * default subscription is defined, the subscription ID associated with this message will be
- * INVALID, which will result in the operation being completed on the subscription associated
- * with logical slot 0. Use {@link #getSmsManagerForSubscriptionId(int)} to ensure the
- * operation is performed on the correct subscription.
+ * <p class="note"><strong>Note:</strong> If {@link #getDefault()} is used to instantiate this
+ * manager on a multi-SIM device, this operation may fail sending the MMS message because no
+ * suitable default subscription could be found. In this case, if {@code sentIntent} is
+ * non-null, then the {@link PendingIntent} will be sent with an error code
+ * {@code RESULT_NO_DEFAULT_SMS_APP}. See {@link #getDefault()} for more information on the
+ * conditions where this operation may fail.
* </p>
*
* @param context application context
@@ -2629,21 +2628,30 @@
}
MmsManager m = (MmsManager) context.getSystemService(Context.MMS_SERVICE);
if (m != null) {
- m.sendMultimediaMessage(getSubscriptionId(), contentUri, locationUrl, configOverrides,
- sentIntent, 0L /* messageId */);
+ resolveSubscriptionForOperation(new SubscriptionResolverResult() {
+ @Override
+ public void onSuccess(int subId) {
+ m.sendMultimediaMessage(subId, contentUri, locationUrl, configOverrides,
+ sentIntent, 0L /* messageId */);
+ }
+
+ @Override
+ public void onFailure() {
+ notifySmsError(sentIntent, RESULT_NO_DEFAULT_SMS_APP);
+ }
+ });
}
}
/**
* Download an MMS message from carrier by a given location URL
*
- * <p class="note"><strong>Note:</strong> This method will never trigger an SMS disambiguation
- * dialog. If this method is called on a device that has multiple active subscriptions, this
- * {@link SmsManager} instance has been created with {@link #getDefault()}, and no user-defined
- * default subscription is defined, the subscription ID associated with this message will be
- * INVALID, which will result in the operation being completed on the subscription associated
- * with logical slot 0. Use {@link #getSmsManagerForSubscriptionId(int)} to ensure the
- * operation is performed on the correct subscription.
+ * <p class="note"><strong>Note:</strong> If {@link #getDefault()} is used to instantiate this
+ * manager on a multi-SIM device, this operation may fail downloading the MMS message because no
+ * suitable default subscription could be found. In this case, if {@code downloadedIntent} is
+ * non-null, then the {@link PendingIntent} will be sent with an error code
+ * {@code RESULT_NO_DEFAULT_SMS_APP}. See {@link #getDefault()} for more information on the
+ * conditions where this operation may fail.
* </p>
*
* @param context application context
@@ -2666,8 +2674,18 @@
}
MmsManager m = (MmsManager) context.getSystemService(Context.MMS_SERVICE);
if (m != null) {
- m.downloadMultimediaMessage(getSubscriptionId(), locationUrl, contentUri,
- configOverrides, downloadedIntent, 0L /* messageId */);
+ resolveSubscriptionForOperation(new SubscriptionResolverResult() {
+ @Override
+ public void onSuccess(int subId) {
+ m.downloadMultimediaMessage(subId, locationUrl, contentUri, configOverrides,
+ downloadedIntent, 0L /* messageId */);
+ }
+
+ @Override
+ public void onFailure() {
+ notifySmsError(downloadedIntent, RESULT_NO_DEFAULT_SMS_APP);
+ }
+ });
}
}
diff --git a/telephony/java/android/telephony/TelephonyManager.java b/telephony/java/android/telephony/TelephonyManager.java
index 4f4a133..a202644 100644
--- a/telephony/java/android/telephony/TelephonyManager.java
+++ b/telephony/java/android/telephony/TelephonyManager.java
@@ -2835,11 +2835,13 @@
};
/**
- * Return a collection of all network types
- * @return network types
+ * Returns an array of all valid network types.
+ *
+ * @return An integer array containing all valid network types in no particular order.
*
* @hide
*/
+ @SystemApi(client = SystemApi.Client.MODULE_LIBRARIES)
public static @NonNull @NetworkType int[] getAllNetworkTypes() {
return NETWORK_TYPES;
}