Merge "MediaPlayer2: remove unused methods"
diff --git a/Android.bp b/Android.bp
index 704ec87..9645ba6 100644
--- a/Android.bp
+++ b/Android.bp
@@ -113,6 +113,7 @@
"core/java/android/content/IOnPrimaryClipChangedListener.aidl",
"core/java/android/content/IRestrictionsManager.aidl",
"core/java/android/content/ISyncAdapter.aidl",
+ "core/java/android/content/ISyncAdapterUnsyncableAccountCallback.aidl",
"core/java/android/content/ISyncContext.aidl",
"core/java/android/content/ISyncServiceAdapter.aidl",
"core/java/android/content/ISyncStatusObserver.aidl",
@@ -243,6 +244,7 @@
"core/java/android/os/storage/IStorageEventListener.aidl",
"core/java/android/os/storage/IStorageShutdownObserver.aidl",
"core/java/android/os/storage/IObbActionListener.aidl",
+ "core/java/android/security/IConfirmationPromptCallback.aidl",
"core/java/android/security/IKeystoreService.aidl",
"core/java/android/security/keymaster/IKeyAttestationApplicationIdProvider.aidl",
"core/java/android/service/autofill/IAutoFillService.aidl",
diff --git a/api/current.txt b/api/current.txt
index 0035e22..70add65 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -6938,7 +6938,7 @@
ctor public BackupManager(android.content.Context);
method public void dataChanged();
method public static void dataChanged(java.lang.String);
- method public int requestRestore(android.app.backup.RestoreObserver);
+ method public deprecated int requestRestore(android.app.backup.RestoreObserver);
}
public class FileBackupHelper implements android.app.backup.BackupHelper {
@@ -8767,6 +8767,7 @@
method public void onSecurityException(android.accounts.Account, android.os.Bundle, java.lang.String, android.content.SyncResult);
method public void onSyncCanceled();
method public void onSyncCanceled(java.lang.Thread);
+ method public boolean onUnsyncableAccount();
field public static final deprecated int LOG_SYNC_DETAILS = 2743; // 0xab7
}
@@ -11206,6 +11207,7 @@
field public static final java.lang.String FEATURE_SENSOR_STEP_DETECTOR = "android.hardware.sensor.stepdetector";
field public static final java.lang.String FEATURE_SIP = "android.software.sip";
field public static final java.lang.String FEATURE_SIP_VOIP = "android.software.sip.voip";
+ field public static final java.lang.String FEATURE_STRONGBOX_KEYSTORE = "android.hardware.strongbox_keystore";
field public static final java.lang.String FEATURE_TELEPHONY = "android.hardware.telephony";
field public static final java.lang.String FEATURE_TELEPHONY_CDMA = "android.hardware.telephony.cdma";
field public static final java.lang.String FEATURE_TELEPHONY_GSM = "android.hardware.telephony.gsm";
@@ -22100,6 +22102,7 @@
method public int getChannelConfiguration();
method public int getChannelCount();
method public android.media.AudioFormat getFormat();
+ method public android.os.PersistableBundle getMetrics();
method public static int getMinBufferSize(int, int, int);
method public int getNotificationMarkerPosition();
method public int getPositionNotificationPeriod();
@@ -22148,6 +22151,14 @@
method public android.media.AudioRecord.Builder setBufferSizeInBytes(int) throws java.lang.IllegalArgumentException;
}
+ public static final class AudioRecord.MetricsConstants {
+ field public static final java.lang.String CHANNELS = "android.media.audiorecord.channels";
+ field public static final java.lang.String ENCODING = "android.media.audiorecord.encoding";
+ field public static final java.lang.String LATENCY = "android.media.audiorecord.latency";
+ field public static final java.lang.String SAMPLERATE = "android.media.audiorecord.samplerate";
+ field public static final java.lang.String SOURCE = "android.media.audiorecord.source";
+ }
+
public static abstract interface AudioRecord.OnRecordPositionUpdateListener {
method public abstract void onMarkerReached(android.media.AudioRecord);
method public abstract void onPeriodicNotification(android.media.AudioRecord);
@@ -22207,6 +22218,7 @@
method public int getChannelCount();
method public android.media.AudioFormat getFormat();
method public static float getMaxVolume();
+ method public android.os.PersistableBundle getMetrics();
method public static int getMinBufferSize(int, int, int);
method public static float getMinVolume();
method protected deprecated int getNativeFrameCount();
@@ -22287,6 +22299,14 @@
method public android.media.AudioTrack.Builder setTransferMode(int) throws java.lang.IllegalArgumentException;
}
+ public static final class AudioTrack.MetricsConstants {
+ field public static final java.lang.String CHANNELMASK = "android.media.audiorecord.channelmask";
+ field public static final java.lang.String CONTENTTYPE = "android.media.audiotrack.type";
+ field public static final java.lang.String SAMPLERATE = "android.media.audiorecord.samplerate";
+ field public static final java.lang.String STREAMTYPE = "android.media.audiotrack.streamtype";
+ field public static final java.lang.String USAGE = "android.media.audiotrack.usage";
+ }
+
public static abstract interface AudioTrack.OnPlaybackPositionUpdateListener {
method public abstract void onMarkerReached(android.media.AudioTrack);
method public abstract void onPeriodicNotification(android.media.AudioTrack);
@@ -23230,6 +23250,7 @@
method public android.media.MediaDrm.KeyRequest getKeyRequest(byte[], byte[], java.lang.String, int, java.util.HashMap<java.lang.String, java.lang.String>) throws android.media.NotProvisionedException;
method public int getMaxHdcpLevel();
method public int getMaxSessionCount();
+ method public android.os.PersistableBundle getMetrics();
method public int getOpenSessionCount();
method public byte[] getPropertyByteArray(java.lang.String);
method public java.lang.String getPropertyString(java.lang.String);
@@ -23317,6 +23338,44 @@
method public java.lang.String getDiagnosticInfo();
}
+ public static final class MediaDrm.MetricsConstants {
+ field public static final java.lang.String CLOSE_SESSION_ERROR_COUNT = "drm.mediadrm.close_session.error.count";
+ field public static final java.lang.String CLOSE_SESSION_ERROR_LIST = "drm.mediadrm.close_session.error.list";
+ field public static final java.lang.String CLOSE_SESSION_OK_COUNT = "drm.mediadrm.close_session.ok.count";
+ field public static final java.lang.String EVENT_KEY_EXPIRED_COUNT = "drm.mediadrm.event.KEY_EXPIRED.count";
+ field public static final java.lang.String EVENT_KEY_NEEDED_COUNT = "drm.mediadrm.event.KEY_NEEDED.count";
+ field public static final java.lang.String EVENT_PROVISION_REQUIRED_COUNT = "drm.mediadrm.event.PROVISION_REQUIRED.count";
+ field public static final java.lang.String EVENT_SESSION_RECLAIMED_COUNT = "drm.mediadrm.event.SESSION_RECLAIMED.count";
+ field public static final java.lang.String EVENT_VENDOR_DEFINED_COUNT = "drm.mediadrm.event.VENDOR_DEFINED.count";
+ field public static final java.lang.String GET_DEVICE_UNIQUE_ID_ERROR_COUNT = "drm.mediadrm.get_device_unique_id.error.count";
+ field public static final java.lang.String GET_DEVICE_UNIQUE_ID_ERROR_LIST = "drm.mediadrm.get_device_unique_id.error.list";
+ field public static final java.lang.String GET_DEVICE_UNIQUE_ID_OK_COUNT = "drm.mediadrm.get_device_unique_id.ok.count";
+ field public static final java.lang.String GET_KEY_REQUEST_ERROR_COUNT = "drm.mediadrm.get_key_request.error.count";
+ field public static final java.lang.String GET_KEY_REQUEST_ERROR_LIST = "drm.mediadrm.get_key_request.error.list";
+ field public static final java.lang.String GET_KEY_REQUEST_OK_COUNT = "drm.mediadrm.get_key_request.ok.count";
+ field public static final java.lang.String GET_KEY_REQUEST_OK_TIME_MICROS = "drm.mediadrm.get_key_request.ok.average_time_micros";
+ field public static final java.lang.String GET_PROVISION_REQUEST_ERROR_COUNT = "drm.mediadrm.get_provision_request.error.count";
+ field public static final java.lang.String GET_PROVISION_REQUEST_ERROR_LIST = "drm.mediadrm.get_provision_request.error.list";
+ field public static final java.lang.String GET_PROVISION_REQUEST_OK_COUNT = "drm.mediadrm.get_provision_request.ok.count";
+ field public static final java.lang.String KEY_STATUS_EXPIRED_COUNT = "drm.mediadrm.key_status.EXPIRED.count";
+ field public static final java.lang.String KEY_STATUS_INTERNAL_ERROR_COUNT = "drm.mediadrm.key_status.INTERNAL_ERROR.count";
+ field public static final java.lang.String KEY_STATUS_OUTPUT_NOT_ALLOWED_COUNT = "drm.mediadrm.key_status_change.OUTPUT_NOT_ALLOWED.count";
+ field public static final java.lang.String KEY_STATUS_PENDING_COUNT = "drm.mediadrm.key_status_change.PENDING.count";
+ field public static final java.lang.String KEY_STATUS_USABLE_COUNT = "drm.mediadrm.key_status_change.USABLE.count";
+ field public static final java.lang.String OPEN_SESSION_ERROR_COUNT = "drm.mediadrm.open_session.error.count";
+ field public static final java.lang.String OPEN_SESSION_ERROR_LIST = "drm.mediadrm.open_session.error.list";
+ field public static final java.lang.String OPEN_SESSION_OK_COUNT = "drm.mediadrm.open_session.ok.count";
+ field public static final java.lang.String PROVIDE_KEY_RESPONSE_ERROR_COUNT = "drm.mediadrm.provide_key_response.error.count";
+ field public static final java.lang.String PROVIDE_KEY_RESPONSE_ERROR_LIST = "drm.mediadrm.provide_key_response.error.list";
+ field public static final java.lang.String PROVIDE_KEY_RESPONSE_OK_COUNT = "drm.mediadrm.provide_key_response.ok.count";
+ field public static final java.lang.String PROVIDE_KEY_RESPONSE_OK_TIME_MICROS = "drm.mediadrm.provide_key_response.ok.average_time_micros";
+ field public static final java.lang.String PROVIDE_PROVISION_RESPONSE_ERROR_COUNT = "drm.mediadrm.provide_provision_response.error.count";
+ field public static final java.lang.String PROVIDE_PROVISION_RESPONSE_ERROR_LIST = "drm.mediadrm.provide_provision_response.error.list";
+ field public static final java.lang.String PROVIDE_PROVISION_RESPONSE_OK_COUNT = "drm.mediadrm.provide_provision_response.ok.count";
+ field public static final java.lang.String SESSION_END_TIMES_MS = "drm.mediadrm.session_end_times_ms";
+ field public static final java.lang.String SESSION_START_TIMES_MS = "drm.mediadrm.session_start_times_ms";
+ }
+
public static abstract interface MediaDrm.OnEventListener {
method public abstract void onEvent(android.media.MediaDrm, byte[], int, int, byte[]);
}
@@ -23356,6 +23415,7 @@
method public java.util.Map<java.util.UUID, byte[]> getPsshInfo();
method public boolean getSampleCryptoInfo(android.media.MediaCodec.CryptoInfo);
method public int getSampleFlags();
+ method public long getSampleSize();
method public long getSampleTime();
method public int getSampleTrackIndex();
method public final int getTrackCount();
@@ -36459,6 +36519,18 @@
field public static final deprecated java.lang.String WINDOW_ANIMATION_SCALE = "window_animation_scale";
}
+ public class SettingsSlicesContract {
+ field public static final java.lang.String AUTHORITY = "android.settings.slices";
+ field public static final android.net.Uri BASE_URI;
+ field public static final java.lang.String KEY_AIRPLANE_MODE = "airplane_mode";
+ field public static final java.lang.String KEY_BATTERY_SAVER = "battery_saver";
+ field public static final java.lang.String KEY_BLUETOOTH = "bluetooth";
+ field public static final java.lang.String KEY_LOCATION = "location";
+ field public static final java.lang.String KEY_WIFI = "wifi";
+ field public static final java.lang.String PATH_SETTING_ACTION = "action";
+ field public static final java.lang.String PATH_SETTING_INTENT = "intent";
+ }
+
public class SyncStateContract {
ctor public SyncStateContract();
}
@@ -38248,7 +38320,6 @@
}
public class StrongBoxUnavailableException extends java.security.ProviderException {
- ctor public StrongBoxUnavailableException();
}
public class UserNotAuthenticatedException extends java.security.InvalidKeyException {
@@ -49857,7 +49928,9 @@
ctor public TextClassification.Options();
method public int describeContents();
method public android.os.LocaleList getDefaultLocales();
+ method public java.util.Calendar getReferenceTime();
method public android.view.textclassifier.TextClassification.Options setDefaultLocales(android.os.LocaleList);
+ method public android.view.textclassifier.TextClassification.Options setReferenceTime(java.util.Calendar);
method public void writeToParcel(android.os.Parcel, int);
field public static final android.os.Parcelable.Creator<android.view.textclassifier.TextClassification.Options> CREATOR;
}
@@ -49882,7 +49955,10 @@
field public static final int ENTITY_PRESET_NONE = 1; // 0x1
field public static final android.view.textclassifier.TextClassifier NO_OP;
field public static final java.lang.String TYPE_ADDRESS = "address";
+ field public static final java.lang.String TYPE_DATE = "date";
+ field public static final java.lang.String TYPE_DATE_TIME = "datetime";
field public static final java.lang.String TYPE_EMAIL = "email";
+ field public static final java.lang.String TYPE_FLIGHT_NUMBER = "flight";
field public static final java.lang.String TYPE_OTHER = "other";
field public static final java.lang.String TYPE_PHONE = "phone";
field public static final java.lang.String TYPE_UNKNOWN = "";
diff --git a/api/system-current.txt b/api/system-current.txt
index 10ce028..6be004c 100644
--- a/api/system-current.txt
+++ b/api/system-current.txt
@@ -361,6 +361,7 @@
method public byte[] getMetadata();
method public boolean removeConfiguration(long);
method public boolean setBroadcastSubscriber(long, long, android.app.PendingIntent);
+ field public static final java.lang.String ACTION_STATSD_STARTED = "android.app.action.STATSD_STARTED";
field public static final java.lang.String EXTRA_STATS_CONFIG_KEY = "android.app.extra.STATS_CONFIG_KEY";
field public static final java.lang.String EXTRA_STATS_CONFIG_UID = "android.app.extra.STATS_CONFIG_UID";
field public static final java.lang.String EXTRA_STATS_DIMENSIONS_VALUE = "android.app.extra.STATS_DIMENSIONS_VALUE";
@@ -450,7 +451,7 @@
method public java.lang.String[] listAllTransports();
method public int requestBackup(java.lang.String[], android.app.backup.BackupObserver);
method public int requestBackup(java.lang.String[], android.app.backup.BackupObserver, android.app.backup.BackupManagerMonitor, int);
- method public int requestRestore(android.app.backup.RestoreObserver, android.app.backup.BackupManagerMonitor);
+ method public deprecated int requestRestore(android.app.backup.RestoreObserver, android.app.backup.BackupManagerMonitor);
method public deprecated java.lang.String selectBackupTransport(java.lang.String);
method public void selectBackupTransport(android.content.ComponentName, android.app.backup.SelectBackupTransportCallback);
method public void setAutoRestore(boolean);
@@ -1043,8 +1044,10 @@
package android.content.pm.dex {
public class ArtManager {
- method public boolean isRuntimeProfilingEnabled();
- method public void snapshotRuntimeProfile(java.lang.String, java.lang.String, android.content.pm.dex.ArtManager.SnapshotRuntimeProfileCallback, android.os.Handler);
+ method public boolean isRuntimeProfilingEnabled(int);
+ method public void snapshotRuntimeProfile(int, java.lang.String, java.lang.String, java.util.concurrent.Executor, android.content.pm.dex.ArtManager.SnapshotRuntimeProfileCallback);
+ field public static final int PROFILE_APPS = 0; // 0x0
+ field public static final int PROFILE_BOOT_IMAGE = 1; // 0x1
field public static final int SNAPSHOT_FAILED_CODE_PATH_NOT_FOUND = 1; // 0x1
field public static final int SNAPSHOT_FAILED_INTERNAL_ERROR = 2; // 0x2
field public static final int SNAPSHOT_FAILED_PACKAGE_NOT_FOUND = 0; // 0x0
@@ -2074,21 +2077,21 @@
method public abstract int cancel();
method public abstract void cancelAnnouncement();
method public abstract void close();
- method public abstract int getConfiguration(android.hardware.radio.RadioManager.BandConfig[]);
+ method public abstract deprecated int getConfiguration(android.hardware.radio.RadioManager.BandConfig[]);
method public android.hardware.radio.ProgramList getDynamicProgramList(android.hardware.radio.ProgramList.Filter);
method public abstract boolean getMute();
method public java.util.Map<java.lang.String, java.lang.String> getParameters(java.util.List<java.lang.String>);
- method public abstract int getProgramInformation(android.hardware.radio.RadioManager.ProgramInfo[]);
+ method public abstract deprecated int getProgramInformation(android.hardware.radio.RadioManager.ProgramInfo[]);
method public abstract deprecated java.util.List<android.hardware.radio.RadioManager.ProgramInfo> getProgramList(java.util.Map<java.lang.String, java.lang.String>);
method public abstract boolean hasControl();
method public abstract deprecated boolean isAnalogForced();
- method public abstract boolean isAntennaConnected();
+ method public abstract deprecated boolean isAntennaConnected();
method public boolean isConfigFlagSet(int);
method public boolean isConfigFlagSupported(int);
method public abstract int scan(int, boolean);
method public abstract deprecated void setAnalogForced(boolean);
method public void setConfigFlag(int, boolean);
- method public abstract int setConfiguration(android.hardware.radio.RadioManager.BandConfig);
+ method public abstract deprecated int setConfiguration(android.hardware.radio.RadioManager.BandConfig);
method public abstract int setMute(boolean);
method public java.util.Map<java.lang.String, java.lang.String> setParameters(java.util.Map<java.lang.String, java.lang.String>);
method public abstract boolean startBackgroundScan();
@@ -2097,13 +2100,13 @@
method public abstract void tune(android.hardware.radio.ProgramSelector);
field public static final int DIRECTION_DOWN = 1; // 0x1
field public static final int DIRECTION_UP = 0; // 0x0
- field public static final int ERROR_BACKGROUND_SCAN_FAILED = 6; // 0x6
- field public static final int ERROR_BACKGROUND_SCAN_UNAVAILABLE = 5; // 0x5
- field public static final int ERROR_CANCELLED = 2; // 0x2
- field public static final int ERROR_CONFIG = 4; // 0x4
- field public static final int ERROR_HARDWARE_FAILURE = 0; // 0x0
- field public static final int ERROR_SCAN_TIMEOUT = 3; // 0x3
- field public static final int ERROR_SERVER_DIED = 1; // 0x1
+ field public static final deprecated int ERROR_BACKGROUND_SCAN_FAILED = 6; // 0x6
+ field public static final deprecated int ERROR_BACKGROUND_SCAN_UNAVAILABLE = 5; // 0x5
+ field public static final deprecated int ERROR_CANCELLED = 2; // 0x2
+ field public static final deprecated int ERROR_CONFIG = 4; // 0x4
+ field public static final deprecated int ERROR_HARDWARE_FAILURE = 0; // 0x0
+ field public static final deprecated int ERROR_SCAN_TIMEOUT = 3; // 0x3
+ field public static final deprecated int ERROR_SERVER_DIED = 1; // 0x1
}
public static abstract class RadioTuner.Callback {
@@ -2111,15 +2114,16 @@
method public void onAntennaState(boolean);
method public void onBackgroundScanAvailabilityChange(boolean);
method public void onBackgroundScanComplete();
- method public void onConfigurationChanged(android.hardware.radio.RadioManager.BandConfig);
+ method public deprecated void onConfigurationChanged(android.hardware.radio.RadioManager.BandConfig);
method public void onControlChanged(boolean);
method public void onEmergencyAnnouncement(boolean);
- method public void onError(int);
+ method public deprecated void onError(int);
method public deprecated void onMetadataChanged(android.hardware.radio.RadioMetadata);
method public void onParametersUpdated(java.util.Map<java.lang.String, java.lang.String>);
method public void onProgramInfoChanged(android.hardware.radio.RadioManager.ProgramInfo);
method public void onProgramListChanged();
method public void onTrafficAnnouncement(boolean);
+ method public void onTuneFailed(int, android.hardware.radio.ProgramSelector);
}
}
@@ -5196,10 +5200,6 @@
package android.view {
- public abstract class Window {
- method public void setDisableWallpaperTouchEvents(boolean);
- }
-
public abstract interface WindowManager implements android.view.ViewManager {
method public abstract android.graphics.Region getCurrentImeTouchRegion();
}
diff --git a/cmds/statsd/Android.mk b/cmds/statsd/Android.mk
index eabbb96..565b092 100644
--- a/cmds/statsd/Android.mk
+++ b/cmds/statsd/Android.mk
@@ -137,7 +137,7 @@
LOCAL_MODULE_CLASS := EXECUTABLES
-LOCAL_INIT_RC := statsd.rc
+#LOCAL_INIT_RC := statsd.rc
include $(BUILD_EXECUTABLE)
diff --git a/cmds/statsd/src/atoms.proto b/cmds/statsd/src/atoms.proto
index 77b156f8..c990296 100644
--- a/cmds/statsd/src/atoms.proto
+++ b/cmds/statsd/src/atoms.proto
@@ -21,7 +21,7 @@
option java_package = "com.android.os";
option java_outer_classname = "AtomsProto";
-import "frameworks/base/core/proto/android/app/activitymanager.proto";
+import "frameworks/base/core/proto/android/app/enums.proto";
/**
* The master atom class. This message defines all of the available
@@ -44,7 +44,7 @@
BleUnoptimizedScanStateChanged ble_unoptimized_scan_state_changed = 3;
BleScanResultReceived ble_scan_result_received = 4;
SensorStateChanged sensor_state_changed = 5;
- GpsScanStateChanged gps_scan_state_changed = 6; // TODO: untested
+ GpsScanStateChanged gps_scan_state_changed = 6;
SyncStateChanged sync_state_changed = 7;
ScheduledJobStateChanged scheduled_job_state_changed = 8;
ScreenBrightnessChanged screen_brightness_changed = 9;
@@ -185,9 +185,8 @@
message UidProcessStateChanged {
optional int32 uid = 1; // TODO: should be a string tagged w/ uid annotation
- // The state.
- // TODO: Use the real (mapped) process states.
- optional android.app.ProcessState state = 2;
+ // The state, from frameworks/base/core/proto/android/app/enums.proto.
+ optional android.app.ProcessStateEnum state = 2;
}
/**
diff --git a/core/java/Android.bp b/core/java/Android.bp
index afa08e6..f7c5c57 100644
--- a/core/java/Android.bp
+++ b/core/java/Android.bp
@@ -11,7 +11,8 @@
// only used by key_store_service
cc_library_shared {
name: "libkeystore_aidl",
- srcs: ["android/security/IKeystoreService.aidl"],
+ srcs: ["android/security/IKeystoreService.aidl",
+ "android/security/IConfirmationPromptCallback.aidl"],
aidl: {
export_aidl_headers: true,
include_dirs: [
diff --git a/core/java/android/app/Activity.java b/core/java/android/app/Activity.java
index f0ef49f..cd029c0 100644
--- a/core/java/android/app/Activity.java
+++ b/core/java/android/app/Activity.java
@@ -6330,8 +6330,6 @@
} else {
writer.print(prefix); writer.println("No AutofillManager");
}
-
- ResourcesManager.getInstance().dump(prefix, writer);
}
/**
diff --git a/core/java/android/app/ActivityManager.java b/core/java/android/app/ActivityManager.java
index 8035058..4d5ac6f 100644
--- a/core/java/android/app/ActivityManager.java
+++ b/core/java/android/app/ActivityManager.java
@@ -28,7 +28,6 @@
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
-import android.content.UriPermission;
import android.content.pm.ActivityInfo;
import android.content.pm.ApplicationInfo;
import android.content.pm.ConfigurationInfo;
@@ -576,18 +575,68 @@
/** @hide Process does not exist. */
public static final int PROCESS_STATE_NONEXISTENT = 19;
- // NOTE: If PROCESS_STATEs are added or changed, then new fields must be added
- // to frameworks/base/core/proto/android/app/activitymanager.proto and the following method must
+ // NOTE: If PROCESS_STATEs are added, then new fields must be added
+ // to frameworks/base/core/proto/android/app/enums.proto and the following method must
// be updated to correctly map between them.
+ // However, if the current ActivityManager values are merely modified, no update should be made
+ // to enums.proto, to which values can only be added but never modified. Note that the proto
+ // versions do NOT have the ordering restrictions of the ActivityManager process state.
/**
- * Maps ActivityManager.PROCESS_STATE_ values to ProcessState enum.
+ * Maps ActivityManager.PROCESS_STATE_ values to enums.proto ProcessStateEnum value.
*
* @param amInt a process state of the form ActivityManager.PROCESS_STATE_
- * @return the value of the corresponding ActivityManager's ProcessState enum.
+ * @return the value of the corresponding enums.proto ProcessStateEnum value.
* @hide
*/
public static final int processStateAmToProto(int amInt) {
- return amInt * 100;
+ switch (amInt) {
+ case PROCESS_STATE_UNKNOWN:
+ return AppProtoEnums.PROCESS_STATE_UNKNOWN;
+ case PROCESS_STATE_PERSISTENT:
+ return AppProtoEnums.PROCESS_STATE_PERSISTENT;
+ case PROCESS_STATE_PERSISTENT_UI:
+ return AppProtoEnums.PROCESS_STATE_PERSISTENT_UI;
+ case PROCESS_STATE_TOP:
+ return AppProtoEnums.PROCESS_STATE_TOP;
+ case PROCESS_STATE_FOREGROUND_SERVICE:
+ return AppProtoEnums.PROCESS_STATE_FOREGROUND_SERVICE;
+ case PROCESS_STATE_BOUND_FOREGROUND_SERVICE:
+ return AppProtoEnums.PROCESS_STATE_BOUND_FOREGROUND_SERVICE;
+ case PROCESS_STATE_IMPORTANT_FOREGROUND:
+ return AppProtoEnums.PROCESS_STATE_IMPORTANT_FOREGROUND;
+ case PROCESS_STATE_IMPORTANT_BACKGROUND:
+ return AppProtoEnums.PROCESS_STATE_IMPORTANT_BACKGROUND;
+ case PROCESS_STATE_TRANSIENT_BACKGROUND:
+ return AppProtoEnums.PROCESS_STATE_TRANSIENT_BACKGROUND;
+ case PROCESS_STATE_BACKUP:
+ return AppProtoEnums.PROCESS_STATE_BACKUP;
+ case PROCESS_STATE_SERVICE:
+ return AppProtoEnums.PROCESS_STATE_SERVICE;
+ case PROCESS_STATE_RECEIVER:
+ return AppProtoEnums.PROCESS_STATE_RECEIVER;
+ case PROCESS_STATE_TOP_SLEEPING:
+ return AppProtoEnums.PROCESS_STATE_TOP_SLEEPING;
+ case PROCESS_STATE_HEAVY_WEIGHT:
+ return AppProtoEnums.PROCESS_STATE_HEAVY_WEIGHT;
+ case PROCESS_STATE_HOME:
+ return AppProtoEnums.PROCESS_STATE_HOME;
+ case PROCESS_STATE_LAST_ACTIVITY:
+ return AppProtoEnums.PROCESS_STATE_LAST_ACTIVITY;
+ case PROCESS_STATE_CACHED_ACTIVITY:
+ return AppProtoEnums.PROCESS_STATE_CACHED_ACTIVITY;
+ case PROCESS_STATE_CACHED_ACTIVITY_CLIENT:
+ return AppProtoEnums.PROCESS_STATE_CACHED_ACTIVITY_CLIENT;
+ case PROCESS_STATE_CACHED_RECENT:
+ return AppProtoEnums.PROCESS_STATE_CACHED_RECENT;
+ case PROCESS_STATE_CACHED_EMPTY:
+ return AppProtoEnums.PROCESS_STATE_CACHED_EMPTY;
+ case PROCESS_STATE_NONEXISTENT:
+ return AppProtoEnums.PROCESS_STATE_NONEXISTENT;
+ default:
+ // ActivityManager process state (amInt)
+ // could not be mapped to an AppProtoEnums ProcessState state.
+ return AppProtoEnums.PROCESS_STATE_UNKNOWN_TO_PROTO;
+ }
}
/** @hide The lowest process state number */
@@ -2686,17 +2735,22 @@
/**
* Permits an application to get the persistent URI permissions granted to another.
*
- * <p>Typically called by Settings.
+ * <p>Typically called by Settings or DocumentsUI, requires
+ * {@code GET_APP_GRANTED_URI_PERMISSIONS}.
*
- * @param packageName application to look for the granted permissions
+ * @param packageName application to look for the granted permissions, or {@code null} to get
+ * granted permissions for all applications
* @return list of granted URI permissions
*
* @hide
*/
- public ParceledListSlice<UriPermission> getGrantedUriPermissions(String packageName) {
+ public ParceledListSlice<GrantedUriPermission> getGrantedUriPermissions(
+ @Nullable String packageName) {
try {
- return getService().getGrantedUriPermissions(packageName,
- UserHandle.myUserId());
+ @SuppressWarnings("unchecked")
+ final ParceledListSlice<GrantedUriPermission> castedList = getService()
+ .getGrantedUriPermissions(packageName, UserHandle.myUserId());
+ return castedList;
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
@@ -2705,7 +2759,7 @@
/**
* Permits an application to clear the persistent URI permissions granted to another.
*
- * <p>Typically called by Settings.
+ * <p>Typically called by Settings, requires {@code CLEAR_APP_GRANTED_URI_PERMISSIONS}.
*
* @param packageName application to clear its granted permissions
*
diff --git a/core/java/android/app/GrantedUriPermission.aidl b/core/java/android/app/GrantedUriPermission.aidl
new file mode 100644
index 0000000..2734af0
--- /dev/null
+++ b/core/java/android/app/GrantedUriPermission.aidl
@@ -0,0 +1,20 @@
+/*
+ * Copyright (C) 2018 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;
+
+/** @hide */
+parcelable GrantedUriPermission;
\ No newline at end of file
diff --git a/core/java/android/app/GrantedUriPermission.java b/core/java/android/app/GrantedUriPermission.java
new file mode 100644
index 0000000..9e84fe1
--- /dev/null
+++ b/core/java/android/app/GrantedUriPermission.java
@@ -0,0 +1,74 @@
+/*
+ * Copyright (C) 2018 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.NonNull;
+import android.annotation.Nullable;
+import android.content.UriPermission;
+import android.net.Uri;
+import android.os.Parcel;
+import android.os.Parcelable;
+
+/**
+ * Represents an {@link UriPermission} granted to a package.
+ *
+ * {@hide}
+ */
+public class GrantedUriPermission implements Parcelable {
+
+ public final Uri uri;
+ public final String packageName;
+
+ public GrantedUriPermission(@NonNull Uri uri, @Nullable String packageName) {
+ this.uri = uri;
+ this.packageName = packageName;
+ }
+
+ @Override
+ public String toString() {
+ return packageName + ":" + uri;
+ }
+
+ @Override
+ public int describeContents() {
+ return 0;
+ }
+
+ @Override
+ public void writeToParcel(Parcel out, int flags) {
+ out.writeParcelable(uri, flags);
+ out.writeString(packageName);
+ }
+
+ public static final Parcelable.Creator<GrantedUriPermission> CREATOR =
+ new Parcelable.Creator<GrantedUriPermission>() {
+ @Override
+ public GrantedUriPermission createFromParcel(Parcel in) {
+ return new GrantedUriPermission(in);
+ }
+
+ @Override
+ public GrantedUriPermission[] newArray(int size) {
+ return new GrantedUriPermission[size];
+ }
+ };
+
+ private GrantedUriPermission(Parcel in) {
+ uri = in.readParcelable(null);
+ packageName = in.readString();
+ }
+}
diff --git a/core/java/android/app/IActivityManager.aidl b/core/java/android/app/IActivityManager.aidl
index 9c15562..5382e66 100644
--- a/core/java/android/app/IActivityManager.aidl
+++ b/core/java/android/app/IActivityManager.aidl
@@ -19,6 +19,7 @@
import android.app.ActivityManager;
import android.app.ApplicationErrorReport;
import android.app.ContentProviderHolder;
+import android.app.GrantedUriPermission;
import android.app.IApplicationThread;
import android.app.IActivityController;
import android.app.IAppTask;
@@ -569,7 +570,7 @@
in Rect tempDockedTaskInsetBounds,
in Rect tempOtherTaskBounds, in Rect tempOtherTaskInsetBounds);
int setVrMode(in IBinder token, boolean enabled, in ComponentName packageName);
- // Gets the URI permissions granted to an arbitrary package.
+ // Gets the URI permissions granted to an arbitrary package (or all packages if null)
// NOTE: this is different from getPersistedUriPermissions(), which returns the URIs the package
// granted to another packages (instead of those granted to it).
ParceledListSlice getGrantedUriPermissions(in String packageName, int userId);
diff --git a/core/java/android/app/LoadedApk.java b/core/java/android/app/LoadedApk.java
index 26f4980..d24d4f3 100644
--- a/core/java/android/app/LoadedApk.java
+++ b/core/java/android/app/LoadedApk.java
@@ -28,6 +28,7 @@
import android.content.pm.IPackageManager;
import android.content.pm.PackageManager;
import android.content.pm.PackageManager.NameNotFoundException;
+import android.content.pm.dex.ArtManager;
import android.content.pm.split.SplitDependencyLoader;
import android.content.res.AssetManager;
import android.content.res.CompatibilityInfo;
@@ -35,7 +36,6 @@
import android.content.res.Resources;
import android.os.Build;
import android.os.Bundle;
-import android.os.Environment;
import android.os.FileUtils;
import android.os.Handler;
import android.os.IBinder;
@@ -49,13 +49,15 @@
import android.util.AndroidRuntimeException;
import android.util.ArrayMap;
import android.util.Log;
-import android.util.LogPrinter;
import android.util.Slog;
import android.util.SparseArray;
import android.view.Display;
import android.view.DisplayAdjustments;
+
import com.android.internal.util.ArrayUtils;
+
import dalvik.system.VMRuntime;
+
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
@@ -749,13 +751,6 @@
}
}
- // Keep in sync with installd (frameworks/native/cmds/installd/commands.cpp).
- private static File getPrimaryProfileFile(String packageName) {
- File profileDir = Environment.getDataProfilesDePackageDirectory(
- UserHandle.myUserId(), packageName);
- return new File(profileDir, "primary.prof");
- }
-
private void setupJitProfileSupport() {
if (!SystemProperties.getBoolean("dalvik.vm.usejitprofiles", false)) {
return;
@@ -783,10 +778,12 @@
return;
}
- final File profileFile = getPrimaryProfileFile(mPackageName);
-
- VMRuntime.registerAppInfo(profileFile.getPath(),
- codePaths.toArray(new String[codePaths.size()]));
+ for (int i = codePaths.size() - 1; i >= 0; i--) {
+ String splitName = i == 0 ? null : mApplicationInfo.splitNames[i - 1];
+ String profileFile = ArtManager.getCurrentProfilePath(
+ mPackageName, UserHandle.myUserId(), splitName);
+ VMRuntime.registerAppInfo(profileFile, new String[] {codePaths.get(i)});
+ }
// Register the app data directory with the reporter. It will
// help deciding whether or not a dex file is the primary apk or a
diff --git a/core/java/android/app/ResourcesManager.java b/core/java/android/app/ResourcesManager.java
index b96e028..fb11272 100644
--- a/core/java/android/app/ResourcesManager.java
+++ b/core/java/android/app/ResourcesManager.java
@@ -21,7 +21,6 @@
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.content.pm.ActivityInfo;
-import android.content.res.ApkAssets;
import android.content.res.AssetManager;
import android.content.res.CompatResources;
import android.content.res.CompatibilityInfo;
@@ -35,7 +34,6 @@
import android.util.ArrayMap;
import android.util.DisplayMetrics;
import android.util.Log;
-import android.util.LruCache;
import android.util.Pair;
import android.util.Slog;
import android.view.Display;
@@ -43,13 +41,9 @@
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.util.ArrayUtils;
-import com.android.internal.util.IndentingPrintWriter;
-import java.io.IOException;
-import java.io.PrintWriter;
import java.lang.ref.WeakReference;
import java.util.ArrayList;
-import java.util.Collection;
import java.util.Objects;
import java.util.WeakHashMap;
import java.util.function.Predicate;
@@ -65,7 +59,12 @@
* Predicate that returns true if a WeakReference is gc'ed.
*/
private static final Predicate<WeakReference<Resources>> sEmptyReferencePredicate =
- weakRef -> weakRef == null || weakRef.get() == null;
+ new Predicate<WeakReference<Resources>>() {
+ @Override
+ public boolean test(WeakReference<Resources> weakRef) {
+ return weakRef == null || weakRef.get() == null;
+ }
+ };
/**
* The global compatibility settings.
@@ -90,48 +89,6 @@
*/
private final ArrayList<WeakReference<Resources>> mResourceReferences = new ArrayList<>();
- private static class ApkKey {
- public final String path;
- public final boolean sharedLib;
- public final boolean overlay;
-
- ApkKey(String path, boolean sharedLib, boolean overlay) {
- this.path = path;
- this.sharedLib = sharedLib;
- this.overlay = overlay;
- }
-
- @Override
- public int hashCode() {
- int result = 1;
- result = 31 * result + this.path.hashCode();
- result = 31 * result + Boolean.hashCode(this.sharedLib);
- result = 31 * result + Boolean.hashCode(this.overlay);
- return result;
- }
-
- @Override
- public boolean equals(Object obj) {
- if (!(obj instanceof ApkKey)) {
- return false;
- }
- ApkKey other = (ApkKey) obj;
- return this.path.equals(other.path) && this.sharedLib == other.sharedLib
- && this.overlay == other.overlay;
- }
- }
-
- /**
- * The ApkAssets we are caching and intend to hold strong references to.
- */
- private final LruCache<ApkKey, ApkAssets> mLoadedApkAssets = new LruCache<>(15);
-
- /**
- * The ApkAssets that are being referenced in the wild that we can reuse, even if they aren't
- * in our LRU cache. Bonus resources :)
- */
- private final ArrayMap<ApkKey, WeakReference<ApkAssets>> mCachedApkAssets = new ArrayMap<>();
-
/**
* Resources and base configuration override associated with an Activity.
*/
@@ -303,41 +260,6 @@
}
}
- private @NonNull ApkAssets loadApkAssets(String path, boolean sharedLib, boolean overlay)
- throws IOException {
- final ApkKey newKey = new ApkKey(path, sharedLib, overlay);
- ApkAssets apkAssets = mLoadedApkAssets.get(newKey);
- if (apkAssets != null) {
- return apkAssets;
- }
-
- // Optimistically check if this ApkAssets exists somewhere else.
- final WeakReference<ApkAssets> apkAssetsRef = mCachedApkAssets.get(newKey);
- if (apkAssetsRef != null) {
- apkAssets = apkAssetsRef.get();
- if (apkAssets != null) {
- mLoadedApkAssets.put(newKey, apkAssets);
- return apkAssets;
- } else {
- // Clean up the reference.
- mCachedApkAssets.remove(newKey);
- }
- }
-
- // We must load this from disk.
- if (overlay) {
- final String idmapPath = "/data/resource-cache/"
- + path.substring(1).replace('/', '@')
- + "@idmap";
- apkAssets = ApkAssets.loadOverlayFromPath(idmapPath, false /*system*/);
- } else {
- apkAssets = ApkAssets.loadFromPath(path, false /*system*/, sharedLib);
- }
- mLoadedApkAssets.put(newKey, apkAssets);
- mCachedApkAssets.put(newKey, new WeakReference<>(apkAssets));
- return apkAssets;
- }
-
/**
* Creates an AssetManager from the paths within the ResourcesKey.
*
@@ -348,15 +270,13 @@
*/
@VisibleForTesting
protected @Nullable AssetManager createAssetManager(@NonNull final ResourcesKey key) {
- final ArrayList<ApkAssets> apkAssets = new ArrayList<>();
+ AssetManager assets = new AssetManager();
// resDir can be null if the 'android' package is creating a new Resources object.
// This is fine, since each AssetManager automatically loads the 'android' package
// already.
if (key.mResDir != null) {
- try {
- apkAssets.add(loadApkAssets(key.mResDir, false /*sharedLib*/, false /*overlay*/));
- } catch (IOException e) {
+ if (assets.addAssetPath(key.mResDir) == 0) {
Log.e(TAG, "failed to add asset path " + key.mResDir);
return null;
}
@@ -364,10 +284,7 @@
if (key.mSplitResDirs != null) {
for (final String splitResDir : key.mSplitResDirs) {
- try {
- apkAssets.add(loadApkAssets(splitResDir, false /*sharedLib*/,
- false /*overlay*/));
- } catch (IOException e) {
+ if (assets.addAssetPath(splitResDir) == 0) {
Log.e(TAG, "failed to add split asset path " + splitResDir);
return null;
}
@@ -376,13 +293,7 @@
if (key.mOverlayDirs != null) {
for (final String idmapPath : key.mOverlayDirs) {
- try {
- apkAssets.add(loadApkAssets(idmapPath, false /*sharedLib*/, true /*overlay*/));
- } catch (IOException e) {
- Log.w(TAG, "failed to add overlay path " + idmapPath);
-
- // continue.
- }
+ assets.addOverlayPath(idmapPath);
}
}
@@ -391,77 +302,16 @@
if (libDir.endsWith(".apk")) {
// Avoid opening files we know do not have resources,
// like code-only .jar files.
- try {
- apkAssets.add(loadApkAssets(libDir, true /*sharedLib*/, false /*overlay*/));
- } catch (IOException e) {
+ if (assets.addAssetPathAsSharedLibrary(libDir) == 0) {
Log.w(TAG, "Asset path '" + libDir +
"' does not exist or contains no resources.");
-
- // continue.
}
}
}
}
-
- AssetManager assets = new AssetManager();
- assets.setApkAssets(apkAssets.toArray(new ApkAssets[apkAssets.size()]),
- false /*invalidateCaches*/);
return assets;
}
- private static <T> int countLiveReferences(Collection<WeakReference<T>> collection) {
- int count = 0;
- for (WeakReference<T> ref : collection) {
- final T value = ref != null ? ref.get() : null;
- if (value != null) {
- count++;
- }
- }
- return count;
- }
-
- /**
- * @hide
- */
- public void dump(String prefix, PrintWriter printWriter) {
- synchronized (this) {
- IndentingPrintWriter pw = new IndentingPrintWriter(printWriter, " ");
- for (int i = 0; i < prefix.length() / 2; i++) {
- pw.increaseIndent();
- }
-
- pw.println("ResourcesManager:");
- pw.increaseIndent();
- pw.print("cached apks: total=");
- pw.print(mLoadedApkAssets.size());
- pw.print(" created=");
- pw.print(mLoadedApkAssets.createCount());
- pw.print(" evicted=");
- pw.print(mLoadedApkAssets.evictionCount());
- pw.print(" hit=");
- pw.print(mLoadedApkAssets.hitCount());
- pw.print(" miss=");
- pw.print(mLoadedApkAssets.missCount());
- pw.print(" max=");
- pw.print(mLoadedApkAssets.maxSize());
- pw.println();
-
- pw.print("total apks: ");
- pw.println(countLiveReferences(mCachedApkAssets.values()));
-
- pw.print("resources: ");
-
- int references = countLiveReferences(mResourceReferences);
- for (ActivityResources activityResources : mActivityResourceReferences.values()) {
- references += countLiveReferences(activityResources.activityResources);
- }
- pw.println(references);
-
- pw.print("resource impls: ");
- pw.println(countLiveReferences(mResourceImpls.values()));
- }
- }
-
private Configuration generateConfig(@NonNull ResourcesKey key, @NonNull DisplayMetrics dm) {
Configuration config;
final boolean isDefaultDisplay = (key.mDisplayId == Display.DEFAULT_DISPLAY);
@@ -780,16 +630,28 @@
// We will create the ResourcesImpl object outside of holding this lock.
}
+ }
- // If we're here, we didn't find a suitable ResourcesImpl to use, so create one now.
- ResourcesImpl resourcesImpl = createResourcesImpl(key);
- if (resourcesImpl == null) {
- return null;
+ // If we're here, we didn't find a suitable ResourcesImpl to use, so create one now.
+ ResourcesImpl resourcesImpl = createResourcesImpl(key);
+ if (resourcesImpl == null) {
+ return null;
+ }
+
+ synchronized (this) {
+ ResourcesImpl existingResourcesImpl = findResourcesImplForKeyLocked(key);
+ if (existingResourcesImpl != null) {
+ if (DEBUG) {
+ Slog.d(TAG, "- got beat! existing impl=" + existingResourcesImpl
+ + " new impl=" + resourcesImpl);
+ }
+ resourcesImpl.getAssets().close();
+ resourcesImpl = existingResourcesImpl;
+ } else {
+ // Add this ResourcesImpl to the cache.
+ mResourceImpls.put(key, new WeakReference<>(resourcesImpl));
}
- // Add this ResourcesImpl to the cache.
- mResourceImpls.put(key, new WeakReference<>(resourcesImpl));
-
final Resources resources;
if (activityToken != null) {
resources = getOrCreateResourcesForActivityLocked(activityToken, classLoader,
diff --git a/core/java/android/app/StatsManager.java b/core/java/android/app/StatsManager.java
index 963fc77..c525c89 100644
--- a/core/java/android/app/StatsManager.java
+++ b/core/java/android/app/StatsManager.java
@@ -54,6 +54,12 @@
"android.app.extra.STATS_DIMENSIONS_VALUE";
/**
+ * Broadcast Action: Statsd has started.
+ * Configurations and PendingIntents can now be sent to it.
+ */
+ public static final String ACTION_STATSD_STARTED = "android.app.action.STATSD_STARTED";
+
+ /**
* Constructor for StatsManagerClient.
*
* @hide
diff --git a/core/java/android/app/backup/BackupManager.java b/core/java/android/app/backup/BackupManager.java
index 12f4483..6ec0969 100644
--- a/core/java/android/app/backup/BackupManager.java
+++ b/core/java/android/app/backup/BackupManager.java
@@ -252,6 +252,8 @@
}
/**
+ * @deprecated Since Android P app can no longer request restoring of its backup.
+ *
* Restore the calling application from backup. The data will be restored from the
* current backup dataset if the application has stored data there, or from
* the dataset used during the last full device setup operation if the current
@@ -269,6 +271,7 @@
*
* @return Zero on success; nonzero on error.
*/
+ @Deprecated
public int requestRestore(RestoreObserver observer) {
return requestRestore(observer, null);
}
@@ -276,6 +279,8 @@
// system APIs start here
/**
+ * @deprecated Since Android P app can no longer request restoring of its backup.
+ *
* Restore the calling application from backup. The data will be restored from the
* current backup dataset if the application has stored data there, or from
* the dataset used during the last full device setup operation if the current
@@ -298,28 +303,12 @@
*
* @hide
*/
+ @Deprecated
@SystemApi
public int requestRestore(RestoreObserver observer, BackupManagerMonitor monitor) {
- int result = -1;
- checkServiceBinder();
- if (sService != null) {
- RestoreSession session = null;
- try {
- IRestoreSession binder = sService.beginRestoreSession(mContext.getPackageName(),
- null);
- if (binder != null) {
- session = new RestoreSession(mContext, binder);
- result = session.restorePackage(mContext.getPackageName(), observer, monitor);
- }
- } catch (RemoteException e) {
- Log.e(TAG, "restoreSelf() unable to contact service");
- } finally {
- if (session != null) {
- session.endRestoreSession();
- }
- }
- }
- return result;
+ Log.w(TAG, "requestRestore(): Since Android P app can no longer request restoring"
+ + " of its backup.");
+ return -1;
}
/**
diff --git a/core/java/android/content/AbstractThreadedSyncAdapter.java b/core/java/android/content/AbstractThreadedSyncAdapter.java
index 2629929..5a1216b7 100644
--- a/core/java/android/content/AbstractThreadedSyncAdapter.java
+++ b/core/java/android/content/AbstractThreadedSyncAdapter.java
@@ -21,6 +21,7 @@
import android.os.Bundle;
import android.os.IBinder;
import android.os.Process;
+import android.os.RemoteException;
import android.os.Trace;
import android.util.Log;
@@ -166,6 +167,12 @@
private class ISyncAdapterImpl extends ISyncAdapter.Stub {
@Override
+ public void onUnsyncableAccount(ISyncAdapterUnsyncableAccountCallback cb)
+ throws RemoteException {
+ cb.onUnsyncableAccountDone(AbstractThreadedSyncAdapter.this.onUnsyncableAccount());
+ }
+
+ @Override
public void startSync(ISyncContext syncContext, String authority, Account account,
Bundle extras) {
if (ENABLE_LOG) {
@@ -374,6 +381,26 @@
}
/**
+ * Allows to defer syncing until all accounts are properly set up.
+ *
+ * <p>Called when a account / authority pair
+ * <ul>
+ * <li>that can be handled by this adapter</li>
+ * <li>{@link ContentResolver#requestSync(SyncRequest) is synced}</li>
+ * <li>and the account/provider {@link ContentResolver#getIsSyncable(Account, String) has
+ * unknown state (<0)}.</li>
+ * </ul>
+ *
+ * <p>This might be called on a different service connection as {@link #onPerformSync}.
+ *
+ * @return If {@code false} syncing is deferred. Returns {@code true} by default, i.e. by
+ * default syncing starts immediately.
+ */
+ public boolean onUnsyncableAccount() {
+ return true;
+ }
+
+ /**
* Perform a sync for this account. SyncAdapter-specific parameters may
* be specified in extras, which is guaranteed to not be null. Invocations
* of this method are guaranteed to be serialized.
diff --git a/core/java/android/content/ISyncAdapter.aidl b/core/java/android/content/ISyncAdapter.aidl
index 4660527..0eb581e 100644
--- a/core/java/android/content/ISyncAdapter.aidl
+++ b/core/java/android/content/ISyncAdapter.aidl
@@ -19,6 +19,7 @@
import android.accounts.Account;
import android.os.Bundle;
import android.content.ISyncContext;
+import android.content.ISyncAdapterUnsyncableAccountCallback;
/**
* Interface used to control the sync activity on a SyncAdapter
@@ -26,6 +27,14 @@
*/
oneway interface ISyncAdapter {
/**
+ * Called before {@link #startSync}. This allows the adapter to defer syncs until the
+ * adapter is ready for the account
+ *
+ * @param cb If called back with {@code false} accounts are not synced.
+ */
+ void onUnsyncableAccount(ISyncAdapterUnsyncableAccountCallback cb);
+
+ /**
* Initiate a sync for this account. SyncAdapter-specific parameters may
* be specified in extras, which is guaranteed to not be null.
*
diff --git a/core/java/android/content/ISyncAdapterUnsyncableAccountCallback.aidl b/core/java/android/content/ISyncAdapterUnsyncableAccountCallback.aidl
new file mode 100644
index 0000000..a738ac2
--- /dev/null
+++ b/core/java/android/content/ISyncAdapterUnsyncableAccountCallback.aidl
@@ -0,0 +1,30 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.content;
+
+/**
+ * Callback for {@link ISyncAdapter#onUnsyncableAccount}
+ * @hide
+ */
+oneway interface ISyncAdapterUnsyncableAccountCallback {
+ /**
+ * Deliver the result for {@link ISyncAdapter#onUnsyncableAccount}
+ *
+ * @param isReady Iff {@code false} account is not synced.
+ */
+ void onUnsyncableAccountDone(boolean isReady);
+}
diff --git a/core/java/android/content/pm/PackageManager.java b/core/java/android/content/pm/PackageManager.java
index df69d80..5a894c7 100644
--- a/core/java/android/content/pm/PackageManager.java
+++ b/core/java/android/content/pm/PackageManager.java
@@ -2604,6 +2604,14 @@
public static final String FEATURE_VR_HEADTRACKING = "android.hardware.vr.headtracking";
/**
+ * Feature for {@link #getSystemAvailableFeatures} and {@link #hasSystemFeature}:
+ * The device has a StrongBox hardware-backed Keystore.
+ */
+ @SdkConstant(SdkConstantType.FEATURE)
+ public static final String FEATURE_STRONGBOX_KEYSTORE =
+ "android.hardware.strongbox_keystore";
+
+ /**
* Action to external storage service to clean out removed apps.
* @hide
*/
@@ -4750,7 +4758,7 @@
PackageParser.Package pkg = parser.parseMonolithicPackage(apkFile, 0);
if ((flags & GET_SIGNATURES) != 0) {
- PackageParser.collectCertificates(pkg, 0);
+ PackageParser.collectCertificates(pkg, false /* skipVerify */);
}
PackageUserState state = new PackageUserState();
return PackageParser.generatePackageInfo(pkg, null, flags, 0, 0, null, state);
diff --git a/core/java/android/content/pm/PackageParser.java b/core/java/android/content/pm/PackageParser.java
index c705ef5..3bb812b 100644
--- a/core/java/android/content/pm/PackageParser.java
+++ b/core/java/android/content/pm/PackageParser.java
@@ -1311,6 +1311,24 @@
}
}
+ private static int loadApkIntoAssetManager(AssetManager assets, String apkPath, int flags)
+ throws PackageParserException {
+ if ((flags & PARSE_MUST_BE_APK) != 0 && !isApkPath(apkPath)) {
+ throw new PackageParserException(INSTALL_PARSE_FAILED_NOT_APK,
+ "Invalid package file: " + apkPath);
+ }
+
+ // The AssetManager guarantees uniqueness for asset paths, so if this asset path
+ // already exists in the AssetManager, addAssetPath will only return the cookie
+ // assigned to it.
+ int cookie = assets.addAssetPath(apkPath);
+ if (cookie == 0) {
+ throw new PackageParserException(INSTALL_PARSE_FAILED_BAD_MANIFEST,
+ "Failed adding asset path: " + apkPath);
+ }
+ return cookie;
+ }
+
private Package parseBaseApk(File apkFile, AssetManager assets, int flags)
throws PackageParserException {
final String apkPath = apkFile.getAbsolutePath();
@@ -1326,15 +1344,13 @@
if (DEBUG_JAR) Slog.d(TAG, "Scanning base APK: " + apkPath);
+ final int cookie = loadApkIntoAssetManager(assets, apkPath, flags);
+
+ Resources res = null;
XmlResourceParser parser = null;
try {
- final int cookie = assets.findCookieForPath(apkPath);
- if (cookie == 0) {
- throw new PackageParserException(INSTALL_PARSE_FAILED_BAD_MANIFEST,
- "Failed adding asset path: " + apkPath);
- }
+ res = new Resources(assets, mMetrics, null);
parser = assets.openXmlResourceParser(cookie, ANDROID_MANIFEST_FILENAME);
- final Resources res = new Resources(assets, mMetrics, null);
final String[] outError = new String[1];
final Package pkg = parseBaseApk(apkPath, res, parser, flags, outError);
@@ -1369,18 +1385,15 @@
if (DEBUG_JAR) Slog.d(TAG, "Scanning split APK: " + apkPath);
+ final int cookie = loadApkIntoAssetManager(assets, apkPath, flags);
+
final Resources res;
XmlResourceParser parser = null;
try {
- // This must always succeed, as the path has been added to the AssetManager before.
- final int cookie = assets.findCookieForPath(apkPath);
- if (cookie == 0) {
- throw new PackageParserException(INSTALL_PARSE_FAILED_BAD_MANIFEST,
- "Failed adding asset path: " + apkPath);
- }
-
- parser = assets.openXmlResourceParser(cookie, ANDROID_MANIFEST_FILENAME);
res = new Resources(assets, mMetrics, null);
+ assets.setConfiguration(0, 0, null, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ Build.VERSION.RESOURCES_SDK_INT);
+ parser = assets.openXmlResourceParser(cookie, ANDROID_MANIFEST_FILENAME);
final String[] outError = new String[1];
pkg = parseSplitApk(pkg, res, parser, flags, splitIndex, outError);
@@ -1484,9 +1497,9 @@
* populating {@link Package#mSigningDetails}. Also asserts that all APK
* contents are signed correctly and consistently.
*/
- public static void collectCertificates(Package pkg, @ParseFlags int parseFlags)
+ public static void collectCertificates(Package pkg, boolean skipVerify)
throws PackageParserException {
- collectCertificatesInternal(pkg, parseFlags);
+ collectCertificatesInternal(pkg, skipVerify);
final int childCount = (pkg.childPackages != null) ? pkg.childPackages.size() : 0;
for (int i = 0; i < childCount; i++) {
Package childPkg = pkg.childPackages.get(i);
@@ -1494,17 +1507,17 @@
}
}
- private static void collectCertificatesInternal(Package pkg, @ParseFlags int parseFlags)
+ private static void collectCertificatesInternal(Package pkg, boolean skipVerify)
throws PackageParserException {
pkg.mSigningDetails = SigningDetails.UNKNOWN;
Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "collectCertificates");
try {
- collectCertificates(pkg, new File(pkg.baseCodePath), parseFlags);
+ collectCertificates(pkg, new File(pkg.baseCodePath), skipVerify);
if (!ArrayUtils.isEmpty(pkg.splitCodePaths)) {
for (int i = 0; i < pkg.splitCodePaths.length; i++) {
- collectCertificates(pkg, new File(pkg.splitCodePaths[i]), parseFlags);
+ collectCertificates(pkg, new File(pkg.splitCodePaths[i]), skipVerify);
}
}
} finally {
@@ -1512,7 +1525,7 @@
}
}
- private static void collectCertificates(Package pkg, File apkFile, @ParseFlags int parseFlags)
+ private static void collectCertificates(Package pkg, File apkFile, boolean skipVerify)
throws PackageParserException {
final String apkPath = apkFile.getAbsolutePath();
@@ -1522,7 +1535,7 @@
minSignatureScheme = SigningDetails.SignatureSchemeVersion.SIGNING_BLOCK_V2;
}
SigningDetails verified;
- if ((parseFlags & PARSE_IS_SYSTEM_DIR) != 0) {
+ if (skipVerify) {
// systemDir APKs are already trusted, save time by not verifying
verified = ApkSignatureVerifier.plsCertsNoVerifyOnlyCerts(
apkPath, minSignatureScheme);
@@ -1582,9 +1595,9 @@
int flags) throws PackageParserException {
final String apkPath = fd != null ? debugPathName : apkFile.getAbsolutePath();
+ ApkAssets apkAssets = null;
XmlResourceParser parser = null;
try {
- final ApkAssets apkAssets;
try {
apkAssets = fd != null
? ApkAssets.loadFromFd(fd, debugPathName, false, false)
@@ -1600,9 +1613,10 @@
if ((flags & PARSE_COLLECT_CERTIFICATES) != 0) {
// TODO: factor signature related items out of Package object
final Package tempPkg = new Package((String) null);
+ final boolean skipVerify = (flags & PARSE_IS_SYSTEM_DIR) != 0;
Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "collectCertificates");
try {
- collectCertificates(tempPkg, apkFile, flags);
+ collectCertificates(tempPkg, apkFile, skipVerify);
} finally {
Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
}
@@ -1620,7 +1634,7 @@
"Failed to parse " + apkPath, e);
} finally {
IoUtils.closeQuietly(parser);
- // TODO(b/72056911): Implement and call close() on ApkAssets.
+ IoUtils.closeQuietly(apkAssets);
}
}
diff --git a/core/java/android/content/pm/dex/ArtManager.java b/core/java/android/content/pm/dex/ArtManager.java
index aa9c46e6..4129398 100644
--- a/core/java/android/content/pm/dex/ArtManager.java
+++ b/core/java/android/content/pm/dex/ArtManager.java
@@ -16,16 +16,22 @@
package android.content.pm.dex;
+import android.annotation.CallbackExecutor;
+import android.annotation.IntDef;
import android.annotation.NonNull;
+import android.annotation.Nullable;
import android.annotation.RequiresPermission;
import android.annotation.SystemApi;
-import android.os.Handler;
-import android.os.Looper;
-import android.os.Message;
+import android.os.Environment;
import android.os.ParcelFileDescriptor;
import android.os.RemoteException;
import android.util.Slog;
+import java.io.File;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.util.concurrent.Executor;
+
/**
* Class for retrieving various kinds of information related to the runtime artifacts of
* packages that are currently installed on the device.
@@ -43,6 +49,20 @@
/** The snapshot failed because of an internal error (e.g. error during opening profiles). */
public static final int SNAPSHOT_FAILED_INTERNAL_ERROR = 2;
+ /** Constant used for applications profiles. */
+ public static final int PROFILE_APPS = 0;
+ /** Constant used for the boot image profile. */
+ public static final int PROFILE_BOOT_IMAGE = 1;
+
+ /** @hide */
+ @IntDef(flag = true, prefix = { "PROFILE_" }, value = {
+ PROFILE_APPS,
+ PROFILE_BOOT_IMAGE,
+ })
+ @Retention(RetentionPolicy.SOURCE)
+ public @interface ProfileType {}
+
+
private IArtManager mArtManager;
/**
@@ -53,41 +73,59 @@
}
/**
- * Snapshots the runtime profile for an apk belonging to the package {@code packageName}.
- * The apk is identified by {@code codePath}. The calling process must have
- * {@code android.permission.READ_RUNTIME_PROFILE} permission.
+ * Snapshots a runtime profile according to the {@code profileType} parameter.
*
- * The result will be posted on {@code handler} using the given {@code callback}.
- * The profile being available as a read-only {@link android.os.ParcelFileDescriptor}.
+ * If {@code profileType} is {@link ArtManager#PROFILE_APPS} the method will snapshot
+ * the profile for for an apk belonging to the package {@code packageName}.
+ * The apk is identified by {@code codePath}.
*
- * @param packageName the target package name
- * @param codePath the code path for which the profile should be retrieved
+ * If {@code profileType} is {@code ArtManager.PROFILE_BOOT_IMAGE} the method will snapshot
+ * the profile for the boot image. In this case {@code codePath can be null}. The parameters
+ * {@code packageName} and {@code codePath} are ignored.
+ *u
+ * The calling process must have {@code android.permission.READ_RUNTIME_PROFILE} permission.
+ *
+ * The result will be posted on the {@code executor} using the given {@code callback}.
+ * The profile will be available as a read-only {@link android.os.ParcelFileDescriptor}.
+ *
+ * This method will throw {@link IllegalStateException} if
+ * {@link ArtManager#isRuntimeProfilingEnabled(int)} does not return true for the given
+ * {@code profileType}.
+ *
+ * @param profileType the type of profile that should be snapshot (boot image or app)
+ * @param packageName the target package name or null if the target is the boot image
+ * @param codePath the code path for which the profile should be retrieved or null if
+ * the target is the boot image
* @param callback the callback which should be used for the result
- * @param handler the handler which should be used to post the result
+ * @param executor the executor which should be used to post the result
*/
@RequiresPermission(android.Manifest.permission.READ_RUNTIME_PROFILES)
- public void snapshotRuntimeProfile(@NonNull String packageName, @NonNull String codePath,
- @NonNull SnapshotRuntimeProfileCallback callback, @NonNull Handler handler) {
+ public void snapshotRuntimeProfile(@ProfileType int profileType, @Nullable String packageName,
+ @Nullable String codePath, @NonNull @CallbackExecutor Executor executor,
+ @NonNull SnapshotRuntimeProfileCallback callback) {
Slog.d(TAG, "Requesting profile snapshot for " + packageName + ":" + codePath);
SnapshotRuntimeProfileCallbackDelegate delegate =
- new SnapshotRuntimeProfileCallbackDelegate(callback, handler.getLooper());
+ new SnapshotRuntimeProfileCallbackDelegate(callback, executor);
try {
- mArtManager.snapshotRuntimeProfile(packageName, codePath, delegate);
+ mArtManager.snapshotRuntimeProfile(profileType, packageName, codePath, delegate);
} catch (RemoteException e) {
e.rethrowAsRuntimeException();
}
}
/**
- * Returns true if runtime profiles are enabled, false otherwise.
+ * Returns true if runtime profiles are enabled for the given type, false otherwise.
*
* The calling process must have {@code android.permission.READ_RUNTIME_PROFILE} permission.
+ *
+ * @param profileType can be either {@link ArtManager#PROFILE_APPS}
+ * or {@link ArtManager#PROFILE_BOOT_IMAGE}
*/
@RequiresPermission(android.Manifest.permission.READ_RUNTIME_PROFILES)
- public boolean isRuntimeProfilingEnabled() {
+ public boolean isRuntimeProfilingEnabled(@ProfileType int profileType) {
try {
- return mArtManager.isRuntimeProfilingEnabled();
+ return mArtManager.isRuntimeProfilingEnabled(profileType);
} catch (RemoteException e) {
e.rethrowAsRuntimeException();
}
@@ -116,41 +154,24 @@
}
private static class SnapshotRuntimeProfileCallbackDelegate
- extends android.content.pm.dex.ISnapshotRuntimeProfileCallback.Stub
- implements Handler.Callback {
- private static final int MSG_SNAPSHOT_OK = 1;
- private static final int MSG_ERROR = 2;
+ extends android.content.pm.dex.ISnapshotRuntimeProfileCallback.Stub {
private final ArtManager.SnapshotRuntimeProfileCallback mCallback;
- private final Handler mHandler;
+ private final Executor mExecutor;
private SnapshotRuntimeProfileCallbackDelegate(
- ArtManager.SnapshotRuntimeProfileCallback callback, Looper looper) {
+ ArtManager.SnapshotRuntimeProfileCallback callback, Executor executor) {
mCallback = callback;
- mHandler = new Handler(looper, this);
+ mExecutor = executor;
}
@Override
- public void onSuccess(ParcelFileDescriptor profileReadFd) {
- mHandler.obtainMessage(MSG_SNAPSHOT_OK, profileReadFd).sendToTarget();
+ public void onSuccess(final ParcelFileDescriptor profileReadFd) {
+ mExecutor.execute(() -> mCallback.onSuccess(profileReadFd));
}
@Override
public void onError(int errCode) {
- mHandler.obtainMessage(MSG_ERROR, errCode, 0).sendToTarget();
- }
-
- @Override
- public boolean handleMessage(Message msg) {
- switch (msg.what) {
- case MSG_SNAPSHOT_OK:
- mCallback.onSuccess((ParcelFileDescriptor) msg.obj);
- break;
- case MSG_ERROR:
- mCallback.onError(msg.arg1);
- break;
- default: return false;
- }
- return true;
+ mExecutor.execute(() -> mCallback.onError(errCode));
}
}
@@ -163,4 +184,27 @@
public static String getProfileName(String splitName) {
return splitName == null ? "primary.prof" : splitName + ".split.prof";
}
+
+ /**
+ * Return the path to the current profile corresponding to given package and split.
+ *
+ * @hide
+ */
+ public static String getCurrentProfilePath(String packageName, int userId, String splitName) {
+ File profileDir = Environment.getDataProfilesDePackageDirectory(userId, packageName);
+ return new File(profileDir, getProfileName(splitName)).getAbsolutePath();
+ }
+
+ /**
+ * Return the snapshot profile file for the given package and profile name.
+ *
+ * KEEP in sync with installd dexopt.cpp.
+ * TODO(calin): inject the snapshot profile name from PM to avoid the dependency.
+ *
+ * @hide
+ */
+ public static File getProfileSnapshotFileForName(String packageName, String profileName) {
+ File profileDir = Environment.getDataRefProfilesDePackageDirectory(packageName);
+ return new File(profileDir, profileName + ".snapshot");
+ }
}
diff --git a/core/java/android/content/pm/dex/IArtManager.aidl b/core/java/android/content/pm/dex/IArtManager.aidl
index 8cbb452..6abfdba 100644
--- a/core/java/android/content/pm/dex/IArtManager.aidl
+++ b/core/java/android/content/pm/dex/IArtManager.aidl
@@ -25,20 +25,34 @@
*/
interface IArtManager {
/**
- * Snapshots the runtime profile for an apk belonging to the package {@param packageName}.
- * The apk is identified by {@param codePath}. The calling process must have
- * {@code android.permission.READ_RUNTIME_PROFILE} permission.
+ * Snapshots a runtime profile according to the {@code profileType} parameter.
*
- * The result will be posted on {@param callback} with the profile being available as a
- * read-only {@link android.os.ParcelFileDescriptor}.
- */
- oneway void snapshotRuntimeProfile(in String packageName,
- in String codePath, in ISnapshotRuntimeProfileCallback callback);
-
- /**
- * Returns true if runtime profiles are enabled, false otherwise.
+ * If {@code profileType} is {@link ArtManager#PROFILE_APPS} the method will snapshot
+ * the profile for for an apk belonging to the package {@code packageName}.
+ * The apk is identified by {@code codePath}.
+ *
+ * If {@code profileType} is {@code ArtManager.PROFILE_BOOT_IMAGE} the method will snapshot
+ * the profile for the boot image. In this case {@code codePath can be null}. The parameters
+ * {@code packageName} and {@code codePath} are ignored.
*
* The calling process must have {@code android.permission.READ_RUNTIME_PROFILE} permission.
+ *
+ * The result will be posted on the {@code executor} using the given {@code callback}.
+ * The profile will be available as a read-only {@link android.os.ParcelFileDescriptor}.
+ *
+ * This method will throw {@link IllegalStateException} if
+ * {@link ArtManager#isRuntimeProfilingEnabled(int)} does not return true for the given
+ * {@code profileType}.
*/
- boolean isRuntimeProfilingEnabled();
+ oneway void snapshotRuntimeProfile(int profileType, in String packageName,
+ in String codePath, in ISnapshotRuntimeProfileCallback callback);
+
+ /**
+ * Returns true if runtime profiles are enabled for the given type, false otherwise.
+ * The type can be can be either {@code ArtManager.PROFILE_APPS}
+ * or {@code ArtManager.PROFILE_BOOT_IMAGE}.
+ *
+ * @param profileType
+ */
+ boolean isRuntimeProfilingEnabled(int profileType);
}
diff --git a/core/java/android/content/pm/split/DefaultSplitAssetLoader.java b/core/java/android/content/pm/split/DefaultSplitAssetLoader.java
index 9e3a8f4..99eb470 100644
--- a/core/java/android/content/pm/split/DefaultSplitAssetLoader.java
+++ b/core/java/android/content/pm/split/DefaultSplitAssetLoader.java
@@ -15,13 +15,10 @@
*/
package android.content.pm.split;
-import static android.content.pm.PackageManager.INSTALL_FAILED_INVALID_APK;
+import static android.content.pm.PackageManager.INSTALL_PARSE_FAILED_BAD_MANIFEST;
import static android.content.pm.PackageManager.INSTALL_PARSE_FAILED_NOT_APK;
import android.content.pm.PackageParser;
-import android.content.pm.PackageParser.PackageParserException;
-import android.content.pm.PackageParser.ParseFlags;
-import android.content.res.ApkAssets;
import android.content.res.AssetManager;
import android.os.Build;
@@ -29,8 +26,6 @@
import libcore.io.IoUtils;
-import java.io.IOException;
-
/**
* Loads the base and split APKs into a single AssetManager.
* @hide
@@ -38,66 +33,68 @@
public class DefaultSplitAssetLoader implements SplitAssetLoader {
private final String mBaseCodePath;
private final String[] mSplitCodePaths;
- private final @ParseFlags int mFlags;
+ private final int mFlags;
+
private AssetManager mCachedAssetManager;
- public DefaultSplitAssetLoader(PackageParser.PackageLite pkg, @ParseFlags int flags) {
+ public DefaultSplitAssetLoader(PackageParser.PackageLite pkg, int flags) {
mBaseCodePath = pkg.baseCodePath;
mSplitCodePaths = pkg.splitCodePaths;
mFlags = flags;
}
- private static ApkAssets loadApkAssets(String path, @ParseFlags int flags)
- throws PackageParserException {
- if ((flags & PackageParser.PARSE_MUST_BE_APK) != 0 && !PackageParser.isApkPath(path)) {
- throw new PackageParserException(INSTALL_PARSE_FAILED_NOT_APK,
- "Invalid package file: " + path);
+ private static void loadApkIntoAssetManager(AssetManager assets, String apkPath, int flags)
+ throws PackageParser.PackageParserException {
+ if ((flags & PackageParser.PARSE_MUST_BE_APK) != 0 && !PackageParser.isApkPath(apkPath)) {
+ throw new PackageParser.PackageParserException(INSTALL_PARSE_FAILED_NOT_APK,
+ "Invalid package file: " + apkPath);
}
- try {
- return ApkAssets.loadFromPath(path);
- } catch (IOException e) {
- throw new PackageParserException(INSTALL_FAILED_INVALID_APK,
- "Failed to load APK at path " + path, e);
+ if (assets.addAssetPath(apkPath) == 0) {
+ throw new PackageParser.PackageParserException(
+ INSTALL_PARSE_FAILED_BAD_MANIFEST,
+ "Failed adding asset path: " + apkPath);
}
}
@Override
- public AssetManager getBaseAssetManager() throws PackageParserException {
+ public AssetManager getBaseAssetManager() throws PackageParser.PackageParserException {
if (mCachedAssetManager != null) {
return mCachedAssetManager;
}
- ApkAssets[] apkAssets = new ApkAssets[(mSplitCodePaths != null
- ? mSplitCodePaths.length : 0) + 1];
+ AssetManager assets = new AssetManager();
+ try {
+ assets.setConfiguration(0, 0, null, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ Build.VERSION.RESOURCES_SDK_INT);
+ loadApkIntoAssetManager(assets, mBaseCodePath, mFlags);
- // Load the base.
- int splitIdx = 0;
- apkAssets[splitIdx++] = loadApkAssets(mBaseCodePath, mFlags);
+ if (!ArrayUtils.isEmpty(mSplitCodePaths)) {
+ for (String apkPath : mSplitCodePaths) {
+ loadApkIntoAssetManager(assets, apkPath, mFlags);
+ }
+ }
- // Load any splits.
- if (!ArrayUtils.isEmpty(mSplitCodePaths)) {
- for (String apkPath : mSplitCodePaths) {
- apkAssets[splitIdx++] = loadApkAssets(apkPath, mFlags);
+ mCachedAssetManager = assets;
+ assets = null;
+ return mCachedAssetManager;
+ } finally {
+ if (assets != null) {
+ IoUtils.closeQuietly(assets);
}
}
-
- AssetManager assets = new AssetManager();
- assets.setConfiguration(0, 0, null, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- Build.VERSION.RESOURCES_SDK_INT);
- assets.setApkAssets(apkAssets, false /*invalidateCaches*/);
-
- mCachedAssetManager = assets;
- return mCachedAssetManager;
}
@Override
- public AssetManager getSplitAssetManager(int splitIdx) throws PackageParserException {
+ public AssetManager getSplitAssetManager(int splitIdx)
+ throws PackageParser.PackageParserException {
return getBaseAssetManager();
}
@Override
public void close() throws Exception {
- IoUtils.closeQuietly(mCachedAssetManager);
+ if (mCachedAssetManager != null) {
+ IoUtils.closeQuietly(mCachedAssetManager);
+ }
}
}
diff --git a/core/java/android/content/pm/split/SplitAssetDependencyLoader.java b/core/java/android/content/pm/split/SplitAssetDependencyLoader.java
index 58eaabf..16023f0 100644
--- a/core/java/android/content/pm/split/SplitAssetDependencyLoader.java
+++ b/core/java/android/content/pm/split/SplitAssetDependencyLoader.java
@@ -15,21 +15,17 @@
*/
package android.content.pm.split;
+import static android.content.pm.PackageManager.INSTALL_PARSE_FAILED_BAD_MANIFEST;
import static android.content.pm.PackageManager.INSTALL_PARSE_FAILED_NOT_APK;
import android.annotation.NonNull;
-import android.content.pm.PackageManager;
import android.content.pm.PackageParser;
-import android.content.pm.PackageParser.PackageParserException;
-import android.content.pm.PackageParser.ParseFlags;
-import android.content.res.ApkAssets;
import android.content.res.AssetManager;
import android.os.Build;
import android.util.SparseArray;
import libcore.io.IoUtils;
-import java.io.IOException;
import java.util.ArrayList;
import java.util.Collections;
@@ -38,15 +34,17 @@
* is to be used when an application opts-in to isolated split loading.
* @hide
*/
-public class SplitAssetDependencyLoader extends SplitDependencyLoader<PackageParserException>
+public class SplitAssetDependencyLoader
+ extends SplitDependencyLoader<PackageParser.PackageParserException>
implements SplitAssetLoader {
private final String[] mSplitPaths;
- private final @ParseFlags int mFlags;
- private final ApkAssets[][] mCachedSplitApks;
- private final AssetManager[] mCachedAssetManagers;
+ private final int mFlags;
+
+ private String[][] mCachedPaths;
+ private AssetManager[] mCachedAssetManagers;
public SplitAssetDependencyLoader(PackageParser.PackageLite pkg,
- SparseArray<int[]> dependencies, @ParseFlags int flags) {
+ SparseArray<int[]> dependencies, int flags) {
super(dependencies);
// The base is inserted into index 0, so we need to shift all the splits by 1.
@@ -55,7 +53,7 @@
System.arraycopy(pkg.splitCodePaths, 0, mSplitPaths, 1, pkg.splitCodePaths.length);
mFlags = flags;
- mCachedSplitApks = new ApkAssets[mSplitPaths.length][];
+ mCachedPaths = new String[mSplitPaths.length][];
mCachedAssetManagers = new AssetManager[mSplitPaths.length];
}
@@ -64,60 +62,58 @@
return mCachedAssetManagers[splitIdx] != null;
}
- private static ApkAssets loadApkAssets(String path, @ParseFlags int flags)
- throws PackageParserException {
- if ((flags & PackageParser.PARSE_MUST_BE_APK) != 0 && !PackageParser.isApkPath(path)) {
- throw new PackageParserException(INSTALL_PARSE_FAILED_NOT_APK,
- "Invalid package file: " + path);
- }
-
- try {
- return ApkAssets.loadFromPath(path);
- } catch (IOException e) {
- throw new PackageParserException(PackageManager.INSTALL_FAILED_INVALID_APK,
- "Failed to load APK at path " + path, e);
- }
- }
-
- private static AssetManager createAssetManagerWithAssets(ApkAssets[] apkAssets) {
+ private static AssetManager createAssetManagerWithPaths(String[] assetPaths, int flags)
+ throws PackageParser.PackageParserException {
final AssetManager assets = new AssetManager();
- assets.setConfiguration(0, 0, null, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- Build.VERSION.RESOURCES_SDK_INT);
- assets.setApkAssets(apkAssets, false /*invalidateCaches*/);
- return assets;
+ try {
+ assets.setConfiguration(0, 0, null, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ Build.VERSION.RESOURCES_SDK_INT);
+
+ for (String assetPath : assetPaths) {
+ if ((flags & PackageParser.PARSE_MUST_BE_APK) != 0 &&
+ !PackageParser.isApkPath(assetPath)) {
+ throw new PackageParser.PackageParserException(INSTALL_PARSE_FAILED_NOT_APK,
+ "Invalid package file: " + assetPath);
+ }
+
+ if (assets.addAssetPath(assetPath) == 0) {
+ throw new PackageParser.PackageParserException(
+ INSTALL_PARSE_FAILED_BAD_MANIFEST,
+ "Failed adding asset path: " + assetPath);
+ }
+ }
+ return assets;
+ } catch (Throwable e) {
+ IoUtils.closeQuietly(assets);
+ throw e;
+ }
}
@Override
protected void constructSplit(int splitIdx, @NonNull int[] configSplitIndices,
- int parentSplitIdx) throws PackageParserException {
- final ArrayList<ApkAssets> assets = new ArrayList<>();
-
- // Include parent ApkAssets.
+ int parentSplitIdx) throws PackageParser.PackageParserException {
+ final ArrayList<String> assetPaths = new ArrayList<>();
if (parentSplitIdx >= 0) {
- Collections.addAll(assets, mCachedSplitApks[parentSplitIdx]);
+ Collections.addAll(assetPaths, mCachedPaths[parentSplitIdx]);
}
- // Include this ApkAssets.
- assets.add(loadApkAssets(mSplitPaths[splitIdx], mFlags));
-
- // Load and include all config splits for this feature.
+ assetPaths.add(mSplitPaths[splitIdx]);
for (int configSplitIdx : configSplitIndices) {
- assets.add(loadApkAssets(mSplitPaths[configSplitIdx], mFlags));
+ assetPaths.add(mSplitPaths[configSplitIdx]);
}
-
- // Cache the results.
- mCachedSplitApks[splitIdx] = assets.toArray(new ApkAssets[assets.size()]);
- mCachedAssetManagers[splitIdx] = createAssetManagerWithAssets(mCachedSplitApks[splitIdx]);
+ mCachedPaths[splitIdx] = assetPaths.toArray(new String[assetPaths.size()]);
+ mCachedAssetManagers[splitIdx] = createAssetManagerWithPaths(mCachedPaths[splitIdx],
+ mFlags);
}
@Override
- public AssetManager getBaseAssetManager() throws PackageParserException {
+ public AssetManager getBaseAssetManager() throws PackageParser.PackageParserException {
loadDependenciesForSplit(0);
return mCachedAssetManagers[0];
}
@Override
- public AssetManager getSplitAssetManager(int idx) throws PackageParserException {
+ public AssetManager getSplitAssetManager(int idx) throws PackageParser.PackageParserException {
// Since we insert the base at position 0, and PackageParser keeps splits separate from
// the base, we need to adjust the index.
loadDependenciesForSplit(idx + 1);
diff --git a/core/java/android/content/res/ApkAssets.java b/core/java/android/content/res/ApkAssets.java
index fd664bc..b087c48 100644
--- a/core/java/android/content/res/ApkAssets.java
+++ b/core/java/android/content/res/ApkAssets.java
@@ -33,8 +33,8 @@
* making the creation of AssetManagers very cheap.
* @hide
*/
-public final class ApkAssets {
- @GuardedBy("this") private final long mNativePtr;
+public final class ApkAssets implements AutoCloseable {
+ @GuardedBy("this") private long mNativePtr;
@GuardedBy("this") private StringBlock mStringBlock;
/**
@@ -127,12 +127,14 @@
@NonNull String getAssetPath() {
synchronized (this) {
+ ensureValidLocked();
return nativeGetAssetPath(mNativePtr);
}
}
CharSequence getStringFromPool(int idx) {
synchronized (this) {
+ ensureValidLocked();
return mStringBlock.get(idx);
}
}
@@ -149,6 +151,7 @@
public @NonNull XmlResourceParser openXml(@NonNull String fileName) throws IOException {
Preconditions.checkNotNull(fileName, "fileName");
synchronized (this) {
+ ensureValidLocked();
long nativeXmlPtr = nativeOpenXml(mNativePtr, fileName);
try (XmlBlock block = new XmlBlock(null, nativeXmlPtr)) {
XmlResourceParser parser = block.newParser();
@@ -167,13 +170,41 @@
*/
public boolean isUpToDate() {
synchronized (this) {
+ ensureValidLocked();
return nativeIsUpToDate(mNativePtr);
}
}
+ /**
+ * Closes the ApkAssets and destroys the underlying native implementation. Further use of the
+ * ApkAssets object will cause exceptions to be thrown.
+ *
+ * Calling close on an already closed ApkAssets does nothing.
+ */
+ @Override
+ public void close() {
+ synchronized (this) {
+ if (mNativePtr == 0) {
+ return;
+ }
+
+ mStringBlock = null;
+ nativeDestroy(mNativePtr);
+ mNativePtr = 0;
+ }
+ }
+
@Override
protected void finalize() throws Throwable {
- nativeDestroy(mNativePtr);
+ if (mNativePtr != 0) {
+ nativeDestroy(mNativePtr);
+ }
+ }
+
+ private void ensureValidLocked() {
+ if (mNativePtr == 0) {
+ throw new RuntimeException("ApkAssets is closed");
+ }
}
private static native long nativeLoad(
diff --git a/core/java/android/content/res/AssetManager.java b/core/java/android/content/res/AssetManager.java
index abaf7014..78370f4 100644
--- a/core/java/android/content/res/AssetManager.java
+++ b/core/java/android/content/res/AssetManager.java
@@ -59,8 +59,6 @@
private static final Object sSync = new Object();
- private static final ApkAssets[] sEmptyApkAssets = new ApkAssets[0];
-
// Not private for LayoutLib's BridgeAssetManager.
@GuardedBy("sSync") static AssetManager sSystem = null;
@@ -216,16 +214,10 @@
*/
public void setApkAssets(@NonNull ApkAssets[] apkAssets, boolean invalidateCaches) {
Preconditions.checkNotNull(apkAssets, "apkAssets");
-
- // Copy the apkAssets, but prepend the system assets (framework + overlays).
- final ApkAssets[] newApkAssets = new ApkAssets[apkAssets.length + sSystemApkAssets.length];
- System.arraycopy(sSystemApkAssets, 0, newApkAssets, 0, sSystemApkAssets.length);
- System.arraycopy(apkAssets, 0, newApkAssets, sSystemApkAssets.length, apkAssets.length);
-
synchronized (this) {
- ensureOpenLocked();
- mApkAssets = newApkAssets;
- nativeSetApkAssets(mObject, mApkAssets, invalidateCaches);
+ ensureValidLocked();
+ mApkAssets = apkAssets;
+ nativeSetApkAssets(mObject, apkAssets, invalidateCaches);
if (invalidateCaches) {
// Invalidate all caches.
invalidateCachesLocked(-1);
@@ -244,37 +236,13 @@
}
/**
- * Returns the set of ApkAssets loaded by this AssetManager. If the AssetManager is closed, this
- * returns a 0-length array.
* @hide
*/
public @NonNull ApkAssets[] getApkAssets() {
synchronized (this) {
- if (mOpen) {
- return mApkAssets;
- }
- }
- return sEmptyApkAssets;
- }
-
- /**
- * Returns a cookie for use with the other APIs of AssetManager.
- * @return 0 if the path was not found, otherwise a positive integer cookie representing
- * this path in the AssetManager.
- * @hide
- */
- public int findCookieForPath(@NonNull String path) {
- Preconditions.checkNotNull(path, "path");
- synchronized (this) {
ensureValidLocked();
- final int count = mApkAssets.length;
- for (int i = 0; i < count; i++) {
- if (path.equals(mApkAssets[i].getAssetPath())) {
- return i + 1;
- }
- }
+ return mApkAssets;
}
- return 0;
}
/**
@@ -354,7 +322,6 @@
* then this implies that ensureValidLocked() also passes.
*/
private void ensureOpenLocked() {
- // If mOpen is true, this implies that mObject != 0.
if (!mOpen) {
throw new RuntimeException("AssetManager has been closed");
}
@@ -1186,7 +1153,6 @@
if (mNumRefs == 0 && mObject != 0) {
nativeDestroy(mObject);
mObject = 0;
- mApkAssets = sEmptyApkAssets;
}
}
diff --git a/core/java/android/hardware/radio/ITuner.aidl b/core/java/android/hardware/radio/ITuner.aidl
index bf5e391..429f1f3 100644
--- a/core/java/android/hardware/radio/ITuner.aidl
+++ b/core/java/android/hardware/radio/ITuner.aidl
@@ -64,8 +64,6 @@
void cancelAnnouncement();
- RadioManager.ProgramInfo getProgramInformation();
-
Bitmap getImage(int id);
/**
@@ -92,6 +90,4 @@
* @return Vendor-specific key-value pairs, must be Map<String, String>
*/
Map getParameters(in List<String> keys);
-
- boolean isAntennaConnected();
}
diff --git a/core/java/android/hardware/radio/ITunerCallback.aidl b/core/java/android/hardware/radio/ITunerCallback.aidl
index 54af30f..b32daa5 100644
--- a/core/java/android/hardware/radio/ITunerCallback.aidl
+++ b/core/java/android/hardware/radio/ITunerCallback.aidl
@@ -17,12 +17,14 @@
package android.hardware.radio;
import android.hardware.radio.ProgramList;
+import android.hardware.radio.ProgramSelector;
import android.hardware.radio.RadioManager;
import android.hardware.radio.RadioMetadata;
/** {@hide} */
oneway interface ITunerCallback {
void onError(int status);
+ void onTuneFailed(int result, in ProgramSelector selector);
void onConfigurationChanged(in RadioManager.BandConfig config);
void onCurrentProgramInfoChanged(in RadioManager.ProgramInfo info);
void onTrafficAnnouncement(boolean active);
diff --git a/core/java/android/hardware/radio/RadioTuner.java b/core/java/android/hardware/radio/RadioTuner.java
index ed20c4a..0edd055 100644
--- a/core/java/android/hardware/radio/RadioTuner.java
+++ b/core/java/android/hardware/radio/RadioTuner.java
@@ -64,7 +64,9 @@
* <li>{@link RadioManager#STATUS_DEAD_OBJECT} if the binder transaction to the native
* service fails, </li>
* </ul>
+ * @deprecated Only applicable for HAL 1.x.
*/
+ @Deprecated
public abstract int setConfiguration(RadioManager.BandConfig config);
/**
@@ -80,7 +82,10 @@
* <li>{@link RadioManager#STATUS_DEAD_OBJECT} if the binder transaction to the native
* service fails, </li>
* </ul>
+ *
+ * @deprecated Only applicable for HAL 1.x.
*/
+ @Deprecated
public abstract int getConfiguration(RadioManager.BandConfig[] config);
@@ -228,7 +233,9 @@
* <li>{@link RadioManager#STATUS_DEAD_OBJECT} if the binder transaction to the native
* service fails, </li>
* </ul>
+ * @deprecated Use {@link onProgramInfoChanged} callback instead.
*/
+ @Deprecated
public abstract int getProgramInformation(RadioManager.ProgramInfo[] info);
/**
@@ -427,7 +434,10 @@
* Get current antenna connection state for current configuration.
* Only valid if a configuration has been applied.
* @return {@code true} if the antenna is connected, {@code false} otherwise.
+ *
+ * @deprecated Use {@link onAntennaState} callback instead
*/
+ @Deprecated
public abstract boolean isAntennaConnected();
/**
@@ -446,20 +456,41 @@
public abstract boolean hasControl();
/** Indicates a failure of radio IC or driver.
- * The application must close and re open the tuner */
+ * The application must close and re open the tuner
+ * @deprecated See {@link onError} callback.
+ */
+ @Deprecated
public static final int ERROR_HARDWARE_FAILURE = 0;
/** Indicates a failure of the radio service.
- * The application must close and re open the tuner */
+ * The application must close and re open the tuner
+ * @deprecated See {@link onError} callback.
+ */
+ @Deprecated
public static final int ERROR_SERVER_DIED = 1;
- /** A pending seek or tune operation was cancelled */
+ /** A pending seek or tune operation was cancelled
+ * @deprecated See {@link onError} callback.
+ */
+ @Deprecated
public static final int ERROR_CANCELLED = 2;
- /** A pending seek or tune operation timed out */
+ /** A pending seek or tune operation timed out
+ * @deprecated See {@link onError} callback.
+ */
+ @Deprecated
public static final int ERROR_SCAN_TIMEOUT = 3;
- /** The requested configuration could not be applied */
+ /** The requested configuration could not be applied
+ * @deprecated See {@link onError} callback.
+ */
+ @Deprecated
public static final int ERROR_CONFIG = 4;
- /** Background scan was interrupted due to hardware becoming temporarily unavailable. */
+ /** Background scan was interrupted due to hardware becoming temporarily unavailable.
+ * @deprecated See {@link onError} callback.
+ */
+ @Deprecated
public static final int ERROR_BACKGROUND_SCAN_UNAVAILABLE = 5;
- /** Background scan failed due to other error, ie. HW failure. */
+ /** Background scan failed due to other error, ie. HW failure.
+ * @deprecated See {@link onError} callback.
+ */
+ @Deprecated
public static final int ERROR_BACKGROUND_SCAN_FAILED = 6;
/**
@@ -473,13 +504,29 @@
* status is one of {@link #ERROR_HARDWARE_FAILURE}, {@link #ERROR_SERVER_DIED},
* {@link #ERROR_CANCELLED}, {@link #ERROR_SCAN_TIMEOUT},
* {@link #ERROR_CONFIG}
+ *
+ * @deprecated Use {@link onTuneFailed} for tune, scan and step;
+ * other use cases (configuration, background scan) are already deprecated.
*/
public void onError(int status) {}
+
+ /**
+ * Called when tune, scan or step operation fails.
+ *
+ * @param result cause of the failure
+ * @param selector ProgramSelector argument of tune that failed;
+ * null for scan and step.
+ */
+ public void onTuneFailed(int result, @Nullable ProgramSelector selector) {}
+
/**
* onConfigurationChanged() is called upon successful completion of
* {@link RadioManager#openTuner(int, RadioManager.BandConfig, boolean, Callback, Handler)}
* or {@link RadioTuner#setConfiguration(RadioManager.BandConfig)}
+ *
+ * @deprecated Only applicable for HAL 1.x.
*/
+ @Deprecated
public void onConfigurationChanged(RadioManager.BandConfig config) {}
/**
diff --git a/core/java/android/hardware/radio/TunerAdapter.java b/core/java/android/hardware/radio/TunerAdapter.java
index 91944bf..85f3115 100644
--- a/core/java/android/hardware/radio/TunerAdapter.java
+++ b/core/java/android/hardware/radio/TunerAdapter.java
@@ -202,15 +202,17 @@
@Override
public int getProgramInformation(RadioManager.ProgramInfo[] info) {
if (info == null || info.length != 1) {
- throw new IllegalArgumentException("The argument must be an array of length 1");
+ Log.e(TAG, "The argument must be an array of length 1");
+ return RadioManager.STATUS_BAD_VALUE;
}
- try {
- info[0] = mTuner.getProgramInformation();
- return RadioManager.STATUS_OK;
- } catch (RemoteException e) {
- Log.e(TAG, "service died", e);
- return RadioManager.STATUS_DEAD_OBJECT;
+
+ RadioManager.ProgramInfo current = mCallback.getCurrentProgramInformation();
+ if (current == null) {
+ Log.w(TAG, "Didn't get program info yet");
+ return RadioManager.STATUS_INVALID_OPERATION;
}
+ info[0] = current;
+ return RadioManager.STATUS_OK;
}
@Override
@@ -288,12 +290,20 @@
@Override
public boolean isAnalogForced() {
- return isConfigFlagSet(RadioManager.CONFIG_FORCE_ANALOG);
+ try {
+ return isConfigFlagSet(RadioManager.CONFIG_FORCE_ANALOG);
+ } catch (UnsupportedOperationException ex) {
+ throw new IllegalStateException(ex);
+ }
}
@Override
public void setAnalogForced(boolean isForced) {
- setConfigFlag(RadioManager.CONFIG_FORCE_ANALOG, isForced);
+ try {
+ setConfigFlag(RadioManager.CONFIG_FORCE_ANALOG, isForced);
+ } catch (UnsupportedOperationException ex) {
+ throw new IllegalStateException(ex);
+ }
}
@Override
@@ -343,11 +353,7 @@
@Override
public boolean isAntennaConnected() {
- try {
- return mTuner.isAntennaConnected();
- } catch (RemoteException e) {
- throw new RuntimeException("service died", e);
- }
+ return mCallback.isAntennaConnected();
}
@Override
diff --git a/core/java/android/hardware/radio/TunerCallbackAdapter.java b/core/java/android/hardware/radio/TunerCallbackAdapter.java
index b299ffe..7437c40 100644
--- a/core/java/android/hardware/radio/TunerCallbackAdapter.java
+++ b/core/java/android/hardware/radio/TunerCallbackAdapter.java
@@ -37,8 +37,12 @@
@NonNull private final Handler mHandler;
@Nullable ProgramList mProgramList;
- @Nullable List<RadioManager.ProgramInfo> mLastCompleteList; // for legacy getProgramList call
+
+ // cache for deprecated methods
+ boolean mIsAntennaConnected = true;
+ @Nullable List<RadioManager.ProgramInfo> mLastCompleteList;
private boolean mDelayedCompleteCallback = false;
+ @Nullable RadioManager.ProgramInfo mCurrentProgramInfo;
TunerCallbackAdapter(@NonNull RadioTuner.Callback callback, @Nullable Handler handler) {
mCallback = callback;
@@ -92,12 +96,46 @@
}
}
+ @Nullable RadioManager.ProgramInfo getCurrentProgramInformation() {
+ synchronized (mLock) {
+ return mCurrentProgramInfo;
+ }
+ }
+
+ boolean isAntennaConnected() {
+ return mIsAntennaConnected;
+ }
+
@Override
public void onError(int status) {
mHandler.post(() -> mCallback.onError(status));
}
@Override
+ public void onTuneFailed(int status, @Nullable ProgramSelector selector) {
+ mHandler.post(() -> mCallback.onTuneFailed(status, selector));
+
+ int errorCode;
+ switch (status) {
+ case RadioManager.STATUS_PERMISSION_DENIED:
+ case RadioManager.STATUS_DEAD_OBJECT:
+ errorCode = RadioTuner.ERROR_SERVER_DIED;
+ break;
+ case RadioManager.STATUS_ERROR:
+ case RadioManager.STATUS_NO_INIT:
+ case RadioManager.STATUS_BAD_VALUE:
+ case RadioManager.STATUS_INVALID_OPERATION:
+ Log.i(TAG, "Got an error with no mapping to the legacy API (" + status
+ + "), doing a best-effort conversion to ERROR_SCAN_TIMEOUT");
+ // fall through
+ case RadioManager.STATUS_TIMED_OUT:
+ default:
+ errorCode = RadioTuner.ERROR_SCAN_TIMEOUT;
+ }
+ mHandler.post(() -> mCallback.onError(errorCode));
+ }
+
+ @Override
public void onConfigurationChanged(RadioManager.BandConfig config) {
mHandler.post(() -> mCallback.onConfigurationChanged(config));
}
@@ -109,6 +147,10 @@
return;
}
+ synchronized (mLock) {
+ mCurrentProgramInfo = info;
+ }
+
mHandler.post(() -> {
mCallback.onProgramInfoChanged(info);
@@ -129,6 +171,7 @@
@Override
public void onAntennaState(boolean connected) {
+ mIsAntennaConnected = connected;
mHandler.post(() -> mCallback.onAntennaState(connected));
}
diff --git a/core/java/android/os/Environment.java b/core/java/android/os/Environment.java
index 62731e8..158041d 100644
--- a/core/java/android/os/Environment.java
+++ b/core/java/android/os/Environment.java
@@ -302,9 +302,8 @@
}
/** {@hide} */
- public static File getProfileSnapshotPath(String packageName, String codePath) {
- return buildPath(buildPath(getDataDirectory(), "misc", "profiles", "ref", packageName,
- "primary.prof.snapshot"));
+ public static File getDataRefProfilesDePackageDirectory(String packageName) {
+ return buildPath(getDataDirectory(), "misc", "profiles", "ref", packageName);
}
/** {@hide} */
diff --git a/core/java/android/os/WorkSource.java b/core/java/android/os/WorkSource.java
index 81d7506..d592000 100644
--- a/core/java/android/os/WorkSource.java
+++ b/core/java/android/os/WorkSource.java
@@ -493,6 +493,29 @@
return mChains;
}
+ /**
+ * DO NOT USE: Hacky API provided solely for {@code GnssLocationProvider}. See
+ * {@code setReturningDiffs} as well.
+ *
+ * @hide
+ */
+ public void transferWorkChains(WorkSource other) {
+ if (mChains != null) {
+ mChains.clear();
+ }
+
+ if (other.mChains == null || other.mChains.isEmpty()) {
+ return;
+ }
+
+ if (mChains == null) {
+ mChains = new ArrayList<>(4);
+ }
+
+ mChains.addAll(other.mChains);
+ other.mChains.clear();
+ }
+
private boolean removeUids(WorkSource other) {
int N1 = mNum;
final int[] uids1 = mUids;
@@ -880,6 +903,13 @@
return mUids[0];
}
+ /**
+ * Return the tag associated with the attribution UID. See (@link #getAttributionUid}.
+ */
+ public String getAttributionTag() {
+ return mTags[0];
+ }
+
// TODO: The following three trivial getters are purely for testing and will be removed
// once we have higher level logic in place, e.g for serializing this WorkChain to a proto,
// diffing it etc.
diff --git a/core/java/android/provider/DocumentsContract.java b/core/java/android/provider/DocumentsContract.java
index e7fd59e..d96316a 100644
--- a/core/java/android/provider/DocumentsContract.java
+++ b/core/java/android/provider/DocumentsContract.java
@@ -738,7 +738,9 @@
private static final String PATH_DOCUMENT = "document";
private static final String PATH_CHILDREN = "children";
private static final String PATH_SEARCH = "search";
- private static final String PATH_TREE = "tree";
+ // TODO(b/72055774): make private again once ScopedAccessProvider is refactored
+ /** {@hide} */
+ public static final String PATH_TREE = "tree";
private static final String PARAM_QUERY = "query";
private static final String PARAM_MANAGE = "manage";
diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java
index cadca24..e957842 100644
--- a/core/java/android/provider/Settings.java
+++ b/core/java/android/provider/Settings.java
@@ -5510,6 +5510,27 @@
public static final String LOCATION_MODE = "location_mode";
/**
+ * The App or module that changes the location mode.
+ * @hide
+ */
+ public static final String LOCATION_CHANGER = "location_changer";
+ /**
+ * The location changer is unknown or unable to detect.
+ * @hide
+ */
+ public static final int LOCATION_CHANGER_UNKNOWN = 0;
+ /**
+ * Location settings in system settings.
+ * @hide
+ */
+ public static final int LOCATION_CHANGER_SYSTEM_SETTINGS = 1;
+ /**
+ * The location icon in drop down notification drawer.
+ * @hide
+ */
+ public static final int LOCATION_CHANGER_QUICK_SETTINGS = 2;
+
+ /**
* Location access disabled.
*
* @deprecated To check location status, use {@link LocationManager#isLocationEnabled()}. To
@@ -7881,6 +7902,7 @@
CLONE_TO_MANAGED_PROFILE.add(DEFAULT_INPUT_METHOD);
CLONE_TO_MANAGED_PROFILE.add(ENABLED_ACCESSIBILITY_SERVICES);
CLONE_TO_MANAGED_PROFILE.add(ENABLED_INPUT_METHODS);
+ CLONE_TO_MANAGED_PROFILE.add(LOCATION_CHANGER);
CLONE_TO_MANAGED_PROFILE.add(LOCATION_MODE);
CLONE_TO_MANAGED_PROFILE.add(LOCATION_PROVIDERS_ALLOWED);
CLONE_TO_MANAGED_PROFILE.add(SELECTED_INPUT_METHOD_SUBTYPE);
diff --git a/core/java/android/provider/SettingsSlicesContract.java b/core/java/android/provider/SettingsSlicesContract.java
new file mode 100644
index 0000000..f79d852
--- /dev/null
+++ b/core/java/android/provider/SettingsSlicesContract.java
@@ -0,0 +1,106 @@
+/*
+ * Copyright (C) 2018 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.provider;
+
+import android.content.ContentResolver;
+import android.net.Uri;
+
+/**
+ * Provides a contract for platform-supported Settings {@link android.app.slice.Slice Slices}.
+ * <p>
+ * Contains definitions for the supported {@link android.app.slice.SliceProvider SliceProvider}
+ * authority, authority {@link Uri}, and key constants.
+ * <p>
+ * {@link android.app.slice.Slice Slice} presenters interested in learning meta-data about the
+ * {@link android.app.slice.Slice Slice} should read the {@link android.app.slice.Slice Slice}
+ * object at runtime.
+ * <p>
+ * {@link Uri} builder example:
+ * <pre>
+ * Uri wifiActionUri = AUTHORITY_URI
+ * .buildUpon()
+ * .appendPath(PATH_SETTING_ACTION)
+ * .appendPath(KEY_WIFI)
+ * .build();
+ * Uri bluetoothIntentUri = AUTHORITY_URI
+ * .buildUpon()
+ * .appendPath(PATH_SETTING_INTENT)
+ * .appendPath(KEY_BLUETOOTH)
+ * .build();
+ * </pre>
+ */
+public class SettingsSlicesContract {
+ private SettingsSlicesContract() {
+ }
+
+ /**
+ * Authority for platform Settings Slices.
+ */
+ public static final String AUTHORITY = "android.settings.slices";
+
+ /**
+ * A content:// style uri to the Settings Slices authority, {@link #AUTHORITY}.
+ */
+ public static final Uri BASE_URI = new Uri.Builder()
+ .scheme(ContentResolver.SCHEME_CONTENT)
+ .authority(AUTHORITY)
+ .build();
+
+ /**
+ * {@link Uri} path indicating that the requested {@link android.app.slice.Slice Slice} should
+ * have inline controls for the corresponding setting.
+ * <p>
+ * This path will only contain Slices defined by keys in this class.
+ */
+ public static final String PATH_SETTING_ACTION = "action";
+
+ /**
+ * {@link Uri} path indicating that the requested {@link android.app.slice.Slice Slice} should
+ * be {@link android.content.Intent Intent}-only.
+ * <p>
+ * {@link android.app.slice.Slice Slices} with actions should use the {@link
+ * #PATH_SETTING_ACTION} path.
+ * <p>
+ * This path will only contain Slices defined by keys in this class
+ */
+ public static final String PATH_SETTING_INTENT = "intent";
+
+ /**
+ * {@link Uri} key for the Airplane Mode setting.
+ */
+ public static final String KEY_AIRPLANE_MODE = "airplane_mode";
+
+ /**
+ * {@link Uri} key for the Battery Saver setting.
+ */
+ public static final String KEY_BATTERY_SAVER = "battery_saver";
+
+ /**
+ * {@link Uri} key for the Bluetooth setting.
+ */
+ public static final String KEY_BLUETOOTH = "bluetooth";
+
+ /**
+ * {@link Uri} key for the Location setting.
+ */
+ public static final String KEY_LOCATION = "location";
+
+ /**
+ * {@link Uri} key for the Wi-fi setting.
+ */
+ public static final String KEY_WIFI = "wifi";
+}
diff --git a/core/java/android/security/IConfirmationPromptCallback.aidl b/core/java/android/security/IConfirmationPromptCallback.aidl
new file mode 100644
index 0000000..96a1a04
--- /dev/null
+++ b/core/java/android/security/IConfirmationPromptCallback.aidl
@@ -0,0 +1,27 @@
+/**
+ * Copyright (c) 2017, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.security;
+
+/**
+ * This must be kept manually in sync with system/security/keystore until AIDL
+ * can generate both Java and C++ bindings.
+ *
+ * @hide
+ */
+interface IConfirmationPromptCallback {
+ oneway void onConfirmationPromptCompleted(in int result, in byte[] dataThatWasConfirmed);
+}
diff --git a/core/java/android/security/IKeystoreService.aidl b/core/java/android/security/IKeystoreService.aidl
index b5496e4..738eb68 100644
--- a/core/java/android/security/IKeystoreService.aidl
+++ b/core/java/android/security/IKeystoreService.aidl
@@ -81,4 +81,7 @@
in String wrappingKeyAlias, in byte[] maskingKey, in KeymasterArguments arguments,
in long rootSid, in long fingerprintSid,
out KeyCharacteristics characteristics);
+ int presentConfirmationPrompt(IBinder listener, String promptText, in byte[] extraData,
+ in String locale, in int uiOptionsAsFlags);
+ int cancelConfirmationPrompt(IBinder listener);
}
diff --git a/core/java/android/util/apk/ApkSignatureSchemeV2Verifier.java b/core/java/android/util/apk/ApkSignatureSchemeV2Verifier.java
index 5a09dab..62222b5 100644
--- a/core/java/android/util/apk/ApkSignatureSchemeV2Verifier.java
+++ b/core/java/android/util/apk/ApkSignatureSchemeV2Verifier.java
@@ -412,6 +412,20 @@
}
}
+ static byte[] generateFsverityRootHash(String apkPath)
+ throws IOException, SignatureNotFoundException, DigestException,
+ NoSuchAlgorithmException {
+ try (RandomAccessFile apk = new RandomAccessFile(apkPath, "r")) {
+ SignatureInfo signatureInfo = findSignature(apk);
+ VerifiedSigner vSigner = verify(apk, false);
+ if (vSigner.verityRootHash == null) {
+ return null;
+ }
+ return ApkVerityBuilder.generateFsverityRootHash(
+ apk, ByteBuffer.wrap(vSigner.verityRootHash), signatureInfo);
+ }
+ }
+
private static boolean isSupportedSignatureAlgorithm(int sigAlgorithm) {
switch (sigAlgorithm) {
case SIGNATURE_RSA_PSS_WITH_SHA256:
diff --git a/core/java/android/util/apk/ApkSignatureSchemeV3Verifier.java b/core/java/android/util/apk/ApkSignatureSchemeV3Verifier.java
index 1b04eb2..ee6fc07 100644
--- a/core/java/android/util/apk/ApkSignatureSchemeV3Verifier.java
+++ b/core/java/android/util/apk/ApkSignatureSchemeV3Verifier.java
@@ -523,6 +523,20 @@
}
}
+ static byte[] generateFsverityRootHash(String apkPath)
+ throws NoSuchAlgorithmException, DigestException, IOException,
+ SignatureNotFoundException {
+ try (RandomAccessFile apk = new RandomAccessFile(apkPath, "r")) {
+ SignatureInfo signatureInfo = findSignature(apk);
+ VerifiedSigner vSigner = verify(apk, false);
+ if (vSigner.verityRootHash == null) {
+ return null;
+ }
+ return ApkVerityBuilder.generateFsverityRootHash(
+ apk, ByteBuffer.wrap(vSigner.verityRootHash), signatureInfo);
+ }
+ }
+
private static boolean isSupportedSignatureAlgorithm(int sigAlgorithm) {
switch (sigAlgorithm) {
case SIGNATURE_RSA_PSS_WITH_SHA256:
diff --git a/core/java/android/util/apk/ApkSignatureVerifier.java b/core/java/android/util/apk/ApkSignatureVerifier.java
index 8794372..de9f55b 100644
--- a/core/java/android/util/apk/ApkSignatureVerifier.java
+++ b/core/java/android/util/apk/ApkSignatureVerifier.java
@@ -427,6 +427,27 @@
}
/**
+ * Generates the FSVerity root hash from FSVerity header, extensions and Merkle tree root hash
+ * in Signing Block.
+ *
+ * @return FSverity root hash
+ */
+ public static byte[] generateFsverityRootHash(String apkPath)
+ throws NoSuchAlgorithmException, DigestException, IOException {
+ // first try v3
+ try {
+ return ApkSignatureSchemeV3Verifier.generateFsverityRootHash(apkPath);
+ } catch (SignatureNotFoundException e) {
+ // try older version
+ }
+ try {
+ return ApkSignatureSchemeV2Verifier.generateFsverityRootHash(apkPath);
+ } catch (SignatureNotFoundException e) {
+ return null;
+ }
+ }
+
+ /**
* Result of a successful APK verification operation.
*/
public static class Result {
diff --git a/core/java/android/view/Window.java b/core/java/android/view/Window.java
index 5bd0782..93b3fc2 100644
--- a/core/java/android/view/Window.java
+++ b/core/java/android/view/Window.java
@@ -25,7 +25,6 @@
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.annotation.StyleRes;
-import android.annotation.SystemApi;
import android.app.WindowConfiguration;
import android.content.Context;
import android.content.pm.ActivityInfo;
@@ -1255,14 +1254,6 @@
}
/** @hide */
- @SystemApi
- public void setDisableWallpaperTouchEvents(boolean disable) {
- setPrivateFlags(disable
- ? WindowManager.LayoutParams.PRIVATE_FLAG_DISABLE_WALLPAPER_TOUCH_EVENTS : 0,
- WindowManager.LayoutParams.PRIVATE_FLAG_DISABLE_WALLPAPER_TOUCH_EVENTS);
- }
-
- /** @hide */
public abstract void alwaysReadCloseOnTouchAttr();
/** @hide */
diff --git a/core/java/android/view/textclassifier/SmartSelection.java b/core/java/android/view/textclassifier/SmartSelection.java
index 2c93a19..8edf97e 100644
--- a/core/java/android/view/textclassifier/SmartSelection.java
+++ b/core/java/android/view/textclassifier/SmartSelection.java
@@ -16,6 +16,7 @@
package android.view.textclassifier;
+import android.annotation.Nullable;
import android.content.res.AssetFileDescriptor;
/**
@@ -146,11 +147,24 @@
final String mCollection;
/** float range: 0 - 1 */
final float mScore;
+ @Nullable final DatetimeParseResult mDatetime;
ClassificationResult(String collection, float score) {
mCollection = collection;
mScore = score;
+ mDatetime = null;
}
+
+ ClassificationResult(String collection, float score, DatetimeParseResult datetime) {
+ mCollection = collection;
+ mScore = score;
+ mDatetime = datetime;
+ }
+ }
+
+ /** Parsed date information for the classification result. */
+ static final class DatetimeParseResult {
+ long mMsSinceEpoch;
}
/** Represents a result of Annotate call. */
diff --git a/core/java/android/view/textclassifier/TextClassification.java b/core/java/android/view/textclassifier/TextClassification.java
index 7089677..54e93d5 100644
--- a/core/java/android/view/textclassifier/TextClassification.java
+++ b/core/java/android/view/textclassifier/TextClassification.java
@@ -36,6 +36,7 @@
import com.android.internal.util.Preconditions;
import java.util.ArrayList;
+import java.util.Calendar;
import java.util.List;
import java.util.Locale;
import java.util.Map;
@@ -592,6 +593,7 @@
public static final class Options implements Parcelable {
private @Nullable LocaleList mDefaultLocales;
+ private @Nullable Calendar mReferenceTime;
public Options() {}
@@ -606,6 +608,16 @@
}
/**
+ * @param referenceTime reference time based on which relative dates (e.g. "tomorrow" should
+ * be interpreted. This should usually be the time when the text was originally
+ * composed. If no reference time is set, now is used.
+ */
+ public Options setReferenceTime(Calendar referenceTime) {
+ mReferenceTime = referenceTime;
+ return this;
+ }
+
+ /**
* @return ordered list of locale preferences that can be used to disambiguate
* the provided text.
*/
@@ -614,6 +626,15 @@
return mDefaultLocales;
}
+ /**
+ * @return reference time based on which relative dates (e.g. "tomorrow") should be
+ * interpreted.
+ */
+ @Nullable
+ public Calendar getReferenceTime() {
+ return mReferenceTime;
+ }
+
@Override
public int describeContents() {
return 0;
@@ -625,6 +646,10 @@
if (mDefaultLocales != null) {
mDefaultLocales.writeToParcel(dest, flags);
}
+ dest.writeInt(mReferenceTime != null ? 1 : 0);
+ if (mReferenceTime != null) {
+ dest.writeSerializable(mReferenceTime);
+ }
}
public static final Parcelable.Creator<Options> CREATOR =
@@ -644,6 +669,9 @@
if (in.readInt() > 0) {
mDefaultLocales = LocaleList.CREATOR.createFromParcel(in);
}
+ if (in.readInt() > 0) {
+ mReferenceTime = (Calendar) in.readSerializable();
+ }
}
}
diff --git a/core/java/android/view/textclassifier/TextClassifier.java b/core/java/android/view/textclassifier/TextClassifier.java
index e9715c5..04ab447 100644
--- a/core/java/android/view/textclassifier/TextClassifier.java
+++ b/core/java/android/view/textclassifier/TextClassifier.java
@@ -47,12 +47,26 @@
/** @hide */
String DEFAULT_LOG_TAG = "androidtc";
+ /** The TextClassifier failed to run. */
String TYPE_UNKNOWN = "";
+ /** The classifier ran, but didn't recognize a known entity. */
String TYPE_OTHER = "other";
+ /** E-mail address (e.g. "noreply@android.com"). */
String TYPE_EMAIL = "email";
+ /** Phone number (e.g. "555-123 456"). */
String TYPE_PHONE = "phone";
+ /** Physical address. */
String TYPE_ADDRESS = "address";
+ /** Web URL. */
String TYPE_URL = "url";
+ /** Time reference that is no more specific than a date. May be absolute such as "01/01/2000" or
+ * relative like "tomorrow". **/
+ String TYPE_DATE = "date";
+ /** Time reference that includes a specific time. May be absolute such as "01/01/2000 5:30pm" or
+ * relative like "tomorrow at 5:30pm". **/
+ String TYPE_DATE_TIME = "datetime";
+ /** Flight number in IATA format. */
+ String TYPE_FLIGHT_NUMBER = "flight";
/** @hide */
@Retention(RetentionPolicy.SOURCE)
@@ -63,6 +77,9 @@
TYPE_PHONE,
TYPE_ADDRESS,
TYPE_URL,
+ TYPE_DATE,
+ TYPE_DATE_TIME,
+ TYPE_FLIGHT_NUMBER,
})
@interface EntityType {}
diff --git a/core/java/android/view/textclassifier/TextClassifierImpl.java b/core/java/android/view/textclassifier/TextClassifierImpl.java
index 7db0e76..f434452 100644
--- a/core/java/android/view/textclassifier/TextClassifierImpl.java
+++ b/core/java/android/view/textclassifier/TextClassifierImpl.java
@@ -18,7 +18,9 @@
import android.annotation.NonNull;
import android.annotation.Nullable;
+import android.app.SearchManager;
import android.content.ComponentName;
+import android.content.ContentUris;
import android.content.Context;
import android.content.Intent;
import android.content.pm.PackageManager;
@@ -28,6 +30,7 @@
import android.os.LocaleList;
import android.os.ParcelFileDescriptor;
import android.provider.Browser;
+import android.provider.CalendarContract;
import android.provider.ContactsContract;
import android.provider.Settings;
import android.text.util.Linkify;
@@ -42,6 +45,7 @@
import java.io.IOException;
import java.util.ArrayList;
import java.util.Arrays;
+import java.util.Calendar;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
@@ -49,6 +53,7 @@
import java.util.Locale;
import java.util.Map;
import java.util.Objects;
+import java.util.concurrent.TimeUnit;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
@@ -73,7 +78,10 @@
TextClassifier.TYPE_ADDRESS,
TextClassifier.TYPE_EMAIL,
TextClassifier.TYPE_PHONE,
- TextClassifier.TYPE_URL));
+ TextClassifier.TYPE_URL,
+ TextClassifier.TYPE_DATE,
+ TextClassifier.TYPE_DATE_TIME,
+ TextClassifier.TYPE_FLIGHT_NUMBER));
private static final List<String> ENTITY_TYPES_BASE =
Collections.unmodifiableList(Arrays.asList(
TextClassifier.TYPE_ADDRESS,
@@ -167,9 +175,8 @@
.classifyText(string, startIndex, endIndex,
getHintFlags(string, startIndex, endIndex));
if (results.length > 0) {
- final TextClassification classificationResult =
- createClassificationResult(results, string, startIndex, endIndex);
- return classificationResult;
+ return createClassificationResult(
+ results, string, startIndex, endIndex, options.getReferenceTime());
}
}
} catch (Throwable t) {
@@ -410,18 +417,24 @@
private TextClassification createClassificationResult(
SmartSelection.ClassificationResult[] classifications,
- String text, int start, int end) {
+ String text, int start, int end, @Nullable Calendar referenceTime) {
final String classifiedText = text.substring(start, end);
final TextClassification.Builder builder = new TextClassification.Builder()
.setText(classifiedText);
final int size = classifications.length;
+ SmartSelection.ClassificationResult highestScoringResult = null;
+ float highestScore = Float.MIN_VALUE;
for (int i = 0; i < size; i++) {
builder.setEntityType(classifications[i].mCollection, classifications[i].mScore);
+ if (classifications[i].mScore > highestScore) {
+ highestScoringResult = classifications[i];
+ highestScore = classifications[i].mScore;
+ }
}
- final String type = getHighestScoringType(classifications);
- addActions(builder, IntentFactory.create(mContext, type, classifiedText));
+ addActions(builder, IntentFactory.create(
+ mContext, referenceTime, highestScoringResult, classifiedText));
return builder.setSignature(getSignature(text, start, end)).build();
}
@@ -441,11 +454,10 @@
}
if (resolveInfo != null && resolveInfo.activityInfo != null) {
final String packageName = resolveInfo.activityInfo.packageName;
- CharSequence label;
+ final String label = IntentFactory.getLabel(mContext, intent);
Drawable icon;
if ("android".equals(packageName)) {
// Requires the chooser to find an activity to handle the intent.
- label = IntentFactory.getLabel(mContext, intent);
icon = null;
} else {
// A default activity will handle the intent.
@@ -455,16 +467,11 @@
if (icon == null) {
icon = resolveInfo.loadIcon(pm);
}
- label = resolveInfo.activityInfo.loadLabel(pm);
- if (label == null) {
- label = resolveInfo.loadLabel(pm);
- }
}
- final String labelString = (label != null) ? label.toString() : null;
if (i == 0) {
- builder.setPrimaryAction(intent, labelString, icon);
+ builder.setPrimaryAction(intent, label, icon);
} else {
- builder.addSecondaryAction(intent, labelString, icon);
+ builder.addSecondaryAction(intent, label, icon);
}
}
}
@@ -483,23 +490,6 @@
return flag;
}
- private static String getHighestScoringType(SmartSelection.ClassificationResult[] types) {
- if (types.length < 1) {
- return "";
- }
-
- String type = types[0].mCollection;
- float highestScore = types[0].mScore;
- final int size = types.length;
- for (int i = 1; i < size; i++) {
- if (types[i].mScore > highestScore) {
- type = types[i].mCollection;
- highestScore = types[i].mScore;
- }
- }
- return type;
- }
-
/**
* Closes the ParcelFileDescriptor and logs any errors that occur.
*/
@@ -514,58 +504,139 @@
/**
* Creates intents based on the classification type.
*/
- private static final class IntentFactory {
+ static final class IntentFactory {
+
+ private static final long MIN_EVENT_FUTURE_MILLIS = TimeUnit.MINUTES.toMillis(5);
+ private static final long DEFAULT_EVENT_DURATION = TimeUnit.HOURS.toMillis(1);
private IntentFactory() {}
@NonNull
- public static List<Intent> create(Context context, String type, String text) {
- final List<Intent> intents = new ArrayList<>();
- type = type.trim().toLowerCase(Locale.ENGLISH);
+ public static List<Intent> create(
+ Context context,
+ @Nullable Calendar referenceTime,
+ SmartSelection.ClassificationResult classification,
+ String text) {
+ final String type = classification.mCollection.trim().toLowerCase(Locale.ENGLISH);
text = text.trim();
switch (type) {
case TextClassifier.TYPE_EMAIL:
- intents.add(new Intent(Intent.ACTION_SENDTO)
- .setData(Uri.parse(String.format("mailto:%s", text))));
- intents.add(new Intent(Intent.ACTION_INSERT_OR_EDIT)
+ return createForEmail(text);
+ case TextClassifier.TYPE_PHONE:
+ return createForPhone(text);
+ case TextClassifier.TYPE_ADDRESS:
+ return createForAddress(text);
+ case TextClassifier.TYPE_URL:
+ return createForUrl(context, text);
+ case TextClassifier.TYPE_DATE:
+ case TextClassifier.TYPE_DATE_TIME:
+ if (classification.mDatetime != null) {
+ Calendar eventTime = Calendar.getInstance();
+ eventTime.setTimeInMillis(classification.mDatetime.mMsSinceEpoch);
+ return createForDatetime(type, referenceTime, eventTime);
+ } else {
+ return new ArrayList<>();
+ }
+ case TextClassifier.TYPE_FLIGHT_NUMBER:
+ return createForFlight(text);
+ default:
+ return new ArrayList<>();
+ }
+ }
+
+ @NonNull
+ private static List<Intent> createForEmail(String text) {
+ return Arrays.asList(
+ new Intent(Intent.ACTION_SENDTO)
+ .setData(Uri.parse(String.format("mailto:%s", text))),
+ new Intent(Intent.ACTION_INSERT_OR_EDIT)
.setType(ContactsContract.Contacts.CONTENT_ITEM_TYPE)
.putExtra(ContactsContract.Intents.Insert.EMAIL, text));
- break;
- case TextClassifier.TYPE_PHONE:
- intents.add(new Intent(Intent.ACTION_DIAL)
- .setData(Uri.parse(String.format("tel:%s", text))));
- intents.add(new Intent(Intent.ACTION_INSERT_OR_EDIT)
+ }
+
+ @NonNull
+ private static List<Intent> createForPhone(String text) {
+ return Arrays.asList(
+ new Intent(Intent.ACTION_DIAL)
+ .setData(Uri.parse(String.format("tel:%s", text))),
+ new Intent(Intent.ACTION_INSERT_OR_EDIT)
.setType(ContactsContract.Contacts.CONTENT_ITEM_TYPE)
- .putExtra(ContactsContract.Intents.Insert.PHONE, text));
- intents.add(new Intent(Intent.ACTION_SENDTO)
+ .putExtra(ContactsContract.Intents.Insert.PHONE, text),
+ new Intent(Intent.ACTION_SENDTO)
.setData(Uri.parse(String.format("smsto:%s", text))));
- break;
- case TextClassifier.TYPE_ADDRESS:
- intents.add(new Intent(Intent.ACTION_VIEW)
- .setData(Uri.parse(String.format("geo:0,0?q=%s", text))));
- break;
- case TextClassifier.TYPE_URL:
- final String httpPrefix = "http://";
- final String httpsPrefix = "https://";
- if (text.toLowerCase().startsWith(httpPrefix)) {
- text = httpPrefix + text.substring(httpPrefix.length());
- } else if (text.toLowerCase().startsWith(httpsPrefix)) {
- text = httpsPrefix + text.substring(httpsPrefix.length());
- } else {
- text = httpPrefix + text;
- }
- intents.add(new Intent(Intent.ACTION_VIEW, Uri.parse(text))
- .putExtra(Browser.EXTRA_APPLICATION_ID, context.getPackageName()));
- break;
+ }
+
+ @NonNull
+ private static List<Intent> createForAddress(String text) {
+ return Arrays.asList(new Intent(Intent.ACTION_VIEW)
+ .setData(Uri.parse(String.format("geo:0,0?q=%s", text))));
+ }
+
+ @NonNull
+ private static List<Intent> createForUrl(Context context, String text) {
+ final String httpPrefix = "http://";
+ final String httpsPrefix = "https://";
+ if (text.toLowerCase().startsWith(httpPrefix)) {
+ text = httpPrefix + text.substring(httpPrefix.length());
+ } else if (text.toLowerCase().startsWith(httpsPrefix)) {
+ text = httpsPrefix + text.substring(httpsPrefix.length());
+ } else {
+ text = httpPrefix + text;
+ }
+ return Arrays.asList(new Intent(Intent.ACTION_VIEW, Uri.parse(text))
+ .putExtra(Browser.EXTRA_APPLICATION_ID, context.getPackageName()));
+ }
+
+ @NonNull
+ private static List<Intent> createForDatetime(
+ String type, @Nullable Calendar referenceTime, Calendar eventTime) {
+ if (referenceTime == null) {
+ // If no reference time was given, use now.
+ referenceTime = Calendar.getInstance();
+ }
+ List<Intent> intents = new ArrayList<>();
+ intents.add(createCalendarViewIntent(eventTime));
+ final long millisSinceReference =
+ eventTime.getTimeInMillis() - referenceTime.getTimeInMillis();
+ if (millisSinceReference > MIN_EVENT_FUTURE_MILLIS) {
+ intents.add(createCalendarCreateEventIntent(eventTime, type));
}
return intents;
}
+ @NonNull
+ private static List<Intent> createForFlight(String text) {
+ return Arrays.asList(new Intent(Intent.ACTION_WEB_SEARCH)
+ .putExtra(SearchManager.QUERY, text));
+ }
+
+ @NonNull
+ private static Intent createCalendarViewIntent(Calendar eventTime) {
+ Uri.Builder builder = CalendarContract.CONTENT_URI.buildUpon();
+ builder.appendPath("time");
+ ContentUris.appendId(builder, eventTime.getTimeInMillis());
+ return new Intent(Intent.ACTION_VIEW).setData(builder.build());
+ }
+
+ @NonNull
+ private static Intent createCalendarCreateEventIntent(
+ Calendar eventTime, @EntityType String type) {
+ final boolean isAllDay = TextClassifier.TYPE_DATE.equals(type);
+ return new Intent(Intent.ACTION_INSERT)
+ .setData(CalendarContract.Events.CONTENT_URI)
+ .putExtra(CalendarContract.EXTRA_EVENT_ALL_DAY, isAllDay)
+ .putExtra(CalendarContract.EXTRA_EVENT_BEGIN_TIME, eventTime.getTimeInMillis())
+ .putExtra(CalendarContract.EXTRA_EVENT_END_TIME,
+ eventTime.getTimeInMillis() + DEFAULT_EVENT_DURATION);
+ }
+
@Nullable
public static String getLabel(Context context, @Nullable Intent intent) {
if (intent == null || intent.getAction() == null) {
return null;
}
+ final String authority =
+ intent.getData() == null ? null : intent.getData().getAuthority();
switch (intent.getAction()) {
case Intent.ACTION_DIAL:
return context.getString(com.android.internal.R.string.dial);
@@ -578,6 +649,11 @@
default:
return null;
}
+ case Intent.ACTION_INSERT:
+ if (CalendarContract.AUTHORITY.equals(authority)) {
+ return context.getString(com.android.internal.R.string.add_calendar_event);
+ }
+ return null;
case Intent.ACTION_INSERT_OR_EDIT:
switch (intent.getDataString()) {
case ContactsContract.Contacts.CONTENT_ITEM_TYPE:
@@ -586,6 +662,9 @@
return null;
}
case Intent.ACTION_VIEW:
+ if (CalendarContract.AUTHORITY.equals(authority)) {
+ return context.getString(com.android.internal.R.string.view_calendar);
+ }
switch (intent.getScheme()) {
case "geo":
return context.getString(com.android.internal.R.string.map);
@@ -595,6 +674,8 @@
default:
return null;
}
+ case Intent.ACTION_WEB_SEARCH:
+ return context.getString(com.android.internal.R.string.view_flight);
default:
return null;
}
diff --git a/core/java/android/widget/VideoView2.java b/core/java/android/widget/VideoView2.java
index 8650c0a..7f0c086 100644
--- a/core/java/android/widget/VideoView2.java
+++ b/core/java/android/widget/VideoView2.java
@@ -23,6 +23,7 @@
import android.media.AudioAttributes;
import android.media.AudioManager;
import android.media.MediaPlayerBase;
+import android.media.session.MediaController;
import android.media.update.ApiLoader;
import android.media.update.VideoView2Provider;
import android.media.update.ViewProvider;
@@ -76,8 +77,8 @@
* If a developer wants to attach a customed MediaControlView2, then set enableControlView attribute
* to false and assign the customed media control widget using {@link #setMediaControlView2}.
* <li> VideoView2 is integrated with MediaPlayer2 while VideoView is integrated with MediaPlayer.
- * <li> VideoView2 is integrated with MediaSession2 and so it responses with media key events.
- * A VideoView2 keeps a MediaSession2 instance internally and connects it to a corresponding
+ * <li> VideoView2 is integrated with MediaSession and so it responses with media key events.
+ * A VideoView2 keeps a MediaSession instance internally and connects it to a corresponding
* MediaControlView2 instance.
* </p>
* </ul>
@@ -159,60 +160,18 @@
return mProvider.getMediaControlView2_impl();
}
- /**
- * Starts playback with the media contents specified by {@link #setVideoURI} and
- * {@link #setVideoPath}.
- * If it has been paused, this method will resume playback from the current position.
- */
- public void start() {
- mProvider.start_impl();
- }
/**
- * Pauses playback.
+ * Returns MediaController instance which is connected with MediaSession that VideoView2 is
+ * using. This method should be called when VideoView2 is attached to window, or it throws
+ * IllegalStateException, since internal MediaSession instance is not available until
+ * this view is attached to window. Please check {@link android.view.View#isAttachedToWindow}
+ * before calling this method.
+ *
+ * @throws IllegalStateException if interal MediaSession is not created yet.
*/
- public void pause() {
- mProvider.pause_impl();
- }
-
- /**
- * Gets the duration of the media content specified by #setVideoURI and #setVideoPath
- * in milliseconds.
- */
- public int getDuration() {
- return mProvider.getDuration_impl();
- }
-
- /**
- * Gets current playback position in milliseconds.
- */
- public int getCurrentPosition() {
- return mProvider.getCurrentPosition_impl();
- }
-
- // TODO: mention about key-frame related behavior.
- /**
- * Moves the media by specified time position.
- * @param msec the offset in milliseconds from the start to seek to.
- */
- public void seekTo(int msec) {
- mProvider.seekTo_impl(msec);
- }
-
- /**
- * Says if the media is currently playing.
- * @return true if the media is playing, false if it is not (eg. paused or stopped).
- */
- public boolean isPlaying() {
- return mProvider.isPlaying_impl();
- }
-
- // TODO: check what will return if it is a local media.
- /**
- * Gets the percentage (0-100) of the content that has been buffered or played so far.
- */
- public int getBufferPercentage() {
- return mProvider.getBufferPercentage_impl();
+ public MediaController getMediaController() {
+ return mProvider.getMediaController_impl();
}
/**
@@ -244,7 +203,6 @@
mProvider.setFullScreen_impl(fullScreen);
}
- // TODO: This should be revised after integration with MediaPlayer2.
/**
* Sets playback speed.
*
@@ -254,21 +212,12 @@
* be reset to the normal speed 1.0f.
* @param speed the playback speed. It should be positive.
*/
+ // TODO: Support this via MediaController2.
public void setSpeed(float speed) {
mProvider.setSpeed_impl(speed);
}
/**
- * Returns current speed setting.
- *
- * If setSpeed() has never been called, returns the default value 1.0f.
- * @return current speed setting
- */
- public float getSpeed() {
- return mProvider.getSpeed_impl();
- }
-
- /**
* Sets which type of audio focus will be requested during the playback, or configures playback
* to not request audio focus. Valid values for focus requests are
* {@link AudioManager#AUDIOFOCUS_GAIN}, {@link AudioManager#AUDIOFOCUS_GAIN_TRANSIENT},
@@ -367,14 +316,6 @@
}
/**
- * Stops playback and release all the resources. This should be called whenever a VideoView2
- * instance is no longer to be used.
- */
- public void stopPlayback() {
- mProvider.stopPlayback_impl();
- }
-
- /**
* Registers a callback to be invoked when the media file is loaded and ready to go.
*
* @param l the callback that will be run.
diff --git a/core/java/com/android/internal/app/IBatteryStats.aidl b/core/java/com/android/internal/app/IBatteryStats.aidl
index d3e807d..514ff76 100644
--- a/core/java/com/android/internal/app/IBatteryStats.aidl
+++ b/core/java/com/android/internal/app/IBatteryStats.aidl
@@ -91,8 +91,7 @@
void noteVibratorOn(int uid, long durationMillis);
void noteVibratorOff(int uid);
- void noteStartGps(int uid);
- void noteStopGps(int uid);
+ void noteGpsChanged(in WorkSource oldSource, in WorkSource newSource);
void noteGpsSignalQuality(int signalLevel);
void noteScreenState(int state);
void noteScreenBrightness(int brightness);
diff --git a/core/java/com/android/internal/app/LocaleStore.java b/core/java/com/android/internal/app/LocaleStore.java
index 2b0b5ee..d247013 100644
--- a/core/java/com/android/internal/app/LocaleStore.java
+++ b/core/java/com/android/internal/app/LocaleStore.java
@@ -146,7 +146,11 @@
private String getLangScriptKey() {
if (mLangScriptKey == null) {
- Locale parentWithScript = getParent(LocaleHelper.addLikelySubtags(mLocale));
+ Locale baseLocale = new Locale.Builder()
+ .setLocale(mLocale)
+ .setExtension(Locale.UNICODE_LOCALE_EXTENSION, "")
+ .build();
+ Locale parentWithScript = getParent(LocaleHelper.addLikelySubtags(baseLocale));
mLangScriptKey =
(parentWithScript == null)
? mLocale.toLanguageTag()
diff --git a/core/java/com/android/internal/os/BatteryStatsImpl.java b/core/java/com/android/internal/os/BatteryStatsImpl.java
index 51f51c2..ee3bec8 100644
--- a/core/java/com/android/internal/os/BatteryStatsImpl.java
+++ b/core/java/com/android/internal/os/BatteryStatsImpl.java
@@ -4587,8 +4587,35 @@
int mGpsNesting;
- public void noteStartGpsLocked(int uid) {
- uid = mapUid(uid);
+ public void noteGpsChangedLocked(WorkSource oldWs, WorkSource newWs) {
+ for (int i = 0; i < newWs.size(); ++i) {
+ noteStartGpsLocked(newWs.get(i), null);
+ }
+
+ for (int i = 0; i < oldWs.size(); ++i) {
+ noteStopGpsLocked((oldWs.get(i)), null);
+ }
+
+ List<WorkChain>[] wcs = WorkSource.diffChains(oldWs, newWs);
+ if (wcs != null) {
+ if (wcs[0] != null) {
+ final List<WorkChain> newChains = wcs[0];
+ for (int i = 0; i < newChains.size(); ++i) {
+ noteStartGpsLocked(-1, newChains.get(i));
+ }
+ }
+
+ if (wcs[1] != null) {
+ final List<WorkChain> goneChains = wcs[1];
+ for (int i = 0; i < goneChains.size(); ++i) {
+ noteStopGpsLocked(-1, goneChains.get(i));
+ }
+ }
+ }
+ }
+
+ private void noteStartGpsLocked(int uid, WorkChain workChain) {
+ uid = getAttributionUid(uid, workChain);
final long elapsedRealtime = mClocks.elapsedRealtime();
final long uptime = mClocks.uptimeMillis();
if (mGpsNesting == 0) {
@@ -4598,11 +4625,19 @@
addHistoryRecordLocked(elapsedRealtime, uptime);
}
mGpsNesting++;
+
+ if (workChain == null) {
+ StatsLog.write_non_chained(StatsLog.GPS_SCAN_STATE_CHANGED, uid, null, 1);
+ } else {
+ StatsLog.write(StatsLog.GPS_SCAN_STATE_CHANGED,
+ workChain.getUids(), workChain.getTags(), 1);
+ }
+
getUidStatsLocked(uid).noteStartGps(elapsedRealtime);
}
- public void noteStopGpsLocked(int uid) {
- uid = mapUid(uid);
+ private void noteStopGpsLocked(int uid, WorkChain workChain) {
+ uid = getAttributionUid(uid, workChain);
final long elapsedRealtime = mClocks.elapsedRealtime();
final long uptime = mClocks.uptimeMillis();
mGpsNesting--;
@@ -4614,6 +4649,14 @@
stopAllGpsSignalQualityTimersLocked(-1);
mGpsSignalQualityBin = -1;
}
+
+ if (workChain == null) {
+ StatsLog.write_non_chained(StatsLog.GPS_SCAN_STATE_CHANGED, uid, null, 0);
+ } else {
+ StatsLog.write(StatsLog.GPS_SCAN_STATE_CHANGED, workChain.getUids(),
+ workChain.getTags(), 0);
+ }
+
getUidStatsLocked(uid).noteStopGps(elapsedRealtime);
}
@@ -9842,9 +9885,7 @@
public void noteStartSensor(int sensor, long elapsedRealtimeMs) {
DualTimer t = getSensorTimerLocked(sensor, /* create= */ true);
t.startRunningLocked(elapsedRealtimeMs);
- if (sensor == Sensor.GPS) {
- StatsLog.write_non_chained(StatsLog.GPS_SCAN_STATE_CHANGED, getUid(), null, 1);
- } else {
+ if (sensor != Sensor.GPS) {
StatsLog.write_non_chained(StatsLog.SENSOR_STATE_CHANGED, getUid(), null, sensor,
1);
}
@@ -9855,14 +9896,9 @@
DualTimer t = getSensorTimerLocked(sensor, false);
if (t != null) {
t.stopRunningLocked(elapsedRealtimeMs);
- if (!t.isRunningLocked()) { // only tell statsd if truly stopped
- if (sensor == Sensor.GPS) {
- StatsLog.write_non_chained(StatsLog.GPS_SCAN_STATE_CHANGED, getUid(), null,
- 0);
- } else {
- StatsLog.write_non_chained(StatsLog.SENSOR_STATE_CHANGED, getUid(), null,
- sensor, 0);
- }
+ if (sensor != Sensor.GPS) {
+ StatsLog.write_non_chained(StatsLog.SENSOR_STATE_CHANGED, getUid(), null,
+ sensor, 0);
}
}
}
diff --git a/core/java/com/android/internal/os/ZygoteInit.java b/core/java/com/android/internal/os/ZygoteInit.java
index 5659470..39279b5 100644
--- a/core/java/com/android/internal/os/ZygoteInit.java
+++ b/core/java/com/android/internal/os/ZygoteInit.java
@@ -583,7 +583,7 @@
installd.dexopt(classPathElement, Process.SYSTEM_UID, packageName,
instructionSet, dexoptNeeded, outputPath, dexFlags, compilerFilter,
uuid, classLoaderContext, seInfo, false /* downgrade */,
- targetSdkVersion);
+ targetSdkVersion, /*profileName*/ null);
} catch (RemoteException | ServiceSpecificException e) {
// Ignore (but log), we need this on the classpath for fallback mode.
Log.w(TAG, "Failed compiling classpath element for system server: "
diff --git a/core/java/com/android/internal/view/menu/MenuPopupHelper.java b/core/java/com/android/internal/view/menu/MenuPopupHelper.java
index 6af41a5..324f923 100644
--- a/core/java/com/android/internal/view/menu/MenuPopupHelper.java
+++ b/core/java/com/android/internal/view/menu/MenuPopupHelper.java
@@ -256,7 +256,7 @@
final int hgrav = Gravity.getAbsoluteGravity(mDropDownGravity,
mAnchorView.getLayoutDirection()) & Gravity.HORIZONTAL_GRAVITY_MASK;
if (hgrav == Gravity.RIGHT) {
- xOffset += mAnchorView.getWidth();
+ xOffset -= mAnchorView.getWidth();
}
popup.setHorizontalOffset(xOffset);
diff --git a/core/java/com/android/internal/view/menu/StandardMenuPopup.java b/core/java/com/android/internal/view/menu/StandardMenuPopup.java
index d9ca5be..445379b 100644
--- a/core/java/com/android/internal/view/menu/StandardMenuPopup.java
+++ b/core/java/com/android/internal/view/menu/StandardMenuPopup.java
@@ -263,7 +263,6 @@
mShownAnchorView, mOverflowOnly, mPopupStyleAttr, mPopupStyleRes);
subPopup.setPresenterCallback(mPresenterCallback);
subPopup.setForceShowIcon(MenuPopup.shouldPreserveIconSpacing(subMenu));
- subPopup.setGravity(mDropDownGravity);
// Pass responsibility for handling onDismiss to the submenu.
subPopup.setOnDismissListener(mOnDismissListener);
@@ -273,8 +272,17 @@
mMenu.close(false /* closeAllMenus */);
// Show the new sub-menu popup at the same location as this popup.
- final int horizontalOffset = mPopup.getHorizontalOffset();
+ int horizontalOffset = mPopup.getHorizontalOffset();
final int verticalOffset = mPopup.getVerticalOffset();
+
+ // As xOffset of parent menu popup is subtracted with Anchor width for Gravity.RIGHT,
+ // So, again to display sub-menu popup in same xOffset, add the Anchor width.
+ final int hgrav = Gravity.getAbsoluteGravity(mDropDownGravity,
+ mAnchorView.getLayoutDirection()) & Gravity.HORIZONTAL_GRAVITY_MASK;
+ if (hgrav == Gravity.RIGHT) {
+ horizontalOffset += mAnchorView.getWidth();
+ }
+
if (subPopup.tryShow(horizontalOffset, verticalOffset)) {
if (mPresenterCallback != null) {
mPresenterCallback.onOpenSubMenu(subMenu);
diff --git a/core/jni/Android.bp b/core/jni/Android.bp
index 102ff95..5751fc9 100644
--- a/core/jni/Android.bp
+++ b/core/jni/Android.bp
@@ -163,6 +163,7 @@
"android_media_AudioTrack.cpp",
"android_media_DeviceCallback.cpp",
"android_media_JetPlayer.cpp",
+ "android_media_MediaMetricsJNI.cpp",
"android_media_RemoteDisplay.cpp",
"android_media_ToneGenerator.cpp",
"android_hardware_Camera.cpp",
@@ -261,6 +262,7 @@
"libselinux",
"libicuuc",
"libmedia",
+ "libmediametrics",
"libaudioclient",
"libjpeg",
"libusbhost",
diff --git a/core/jni/android_media_AudioRecord.cpp b/core/jni/android_media_AudioRecord.cpp
index e4da3c6..ebd16c7 100644
--- a/core/jni/android_media_AudioRecord.cpp
+++ b/core/jni/android_media_AudioRecord.cpp
@@ -31,6 +31,7 @@
#include "android_media_AudioFormat.h"
#include "android_media_AudioErrors.h"
#include "android_media_DeviceCallback.h"
+#include "android_media_MediaMetricsJNI.h"
// ----------------------------------------------------------------------------
@@ -751,6 +752,39 @@
}
// ----------------------------------------------------------------------------
+static jobject
+android_media_AudioRecord_native_getMetrics(JNIEnv *env, jobject thiz)
+{
+ ALOGV("android_media_AudioRecord_native_getMetrics");
+
+ sp<AudioRecord> lpRecord = getAudioRecord(env, thiz);
+
+ if (lpRecord == NULL) {
+ ALOGE("Unable to retrieve AudioRecord pointer for getMetrics()");
+ jniThrowException(env, "java/lang/IllegalStateException", NULL);
+ return (jobject) NULL;
+ }
+
+ // get what we have for the metrics from the record session
+ MediaAnalyticsItem *item = NULL;
+
+ status_t err = lpRecord->getMetrics(item);
+ if (err != OK) {
+ ALOGE("getMetrics failed");
+ jniThrowException(env, "java/lang/IllegalStateException", NULL);
+ return (jobject) NULL;
+ }
+
+ jobject mybundle = MediaMetricsJNI::writeMetricsToBundle(env, item, NULL /* mybundle */);
+
+ // housekeeping
+ delete item;
+ item = NULL;
+
+ return mybundle;
+}
+
+// ----------------------------------------------------------------------------
// ----------------------------------------------------------------------------
static const JNINativeMethod gMethods[] = {
// name, signature, funcPtr
@@ -781,6 +815,8 @@
"()I", (void *)android_media_AudioRecord_get_pos_update_period},
{"native_get_min_buff_size",
"(III)I", (void *)android_media_AudioRecord_get_min_buff_size},
+ {"native_getMetrics", "()Landroid/os/PersistableBundle;",
+ (void *)android_media_AudioRecord_native_getMetrics},
{"native_setInputDevice", "(I)Z", (void *)android_media_AudioRecord_setInputDevice},
{"native_getRoutedDeviceId", "()I", (void *)android_media_AudioRecord_getRoutedDeviceId},
{"native_enableDeviceCallback", "()V", (void *)android_media_AudioRecord_enableDeviceCallback},
diff --git a/core/jni/android_media_AudioTrack.cpp b/core/jni/android_media_AudioTrack.cpp
index 11011b1..afbc579 100644
--- a/core/jni/android_media_AudioTrack.cpp
+++ b/core/jni/android_media_AudioTrack.cpp
@@ -34,6 +34,7 @@
#include "android_media_AudioFormat.h"
#include "android_media_AudioErrors.h"
+#include "android_media_MediaMetricsJNI.h"
#include "android_media_PlaybackParams.h"
#include "android_media_DeviceCallback.h"
#include "android_media_VolumeShaper.h"
@@ -1011,6 +1012,39 @@
return (jint) nativeToJavaStatus(status);
}
+// ----------------------------------------------------------------------------
+static jobject
+android_media_AudioTrack_native_getMetrics(JNIEnv *env, jobject thiz)
+{
+ ALOGD("android_media_AudioTrack_native_getMetrics");
+
+ sp<AudioTrack> lpTrack = getAudioTrack(env, thiz);
+
+ if (lpTrack == NULL) {
+ ALOGE("Unable to retrieve AudioTrack pointer for getMetrics()");
+ jniThrowException(env, "java/lang/IllegalStateException", NULL);
+ return (jobject) NULL;
+ }
+
+ // get what we have for the metrics from the track
+ MediaAnalyticsItem *item = NULL;
+
+ status_t err = lpTrack->getMetrics(item);
+ if (err != OK) {
+ ALOGE("getMetrics failed");
+ jniThrowException(env, "java/lang/IllegalStateException", NULL);
+ return (jobject) NULL;
+ }
+
+ jobject mybundle = MediaMetricsJNI::writeMetricsToBundle(env, item, NULL /* mybundle */);
+
+ // housekeeping
+ delete item;
+ item = NULL;
+
+ return mybundle;
+}
+
// ----------------------------------------------------------------------------
static jint android_media_AudioTrack_set_loop(JNIEnv *env, jobject thiz,
@@ -1275,6 +1309,8 @@
{"native_get_underrun_count", "()I", (void *)android_media_AudioTrack_get_underrun_count},
{"native_get_flags", "()I", (void *)android_media_AudioTrack_get_flags},
{"native_get_timestamp", "([J)I", (void *)android_media_AudioTrack_get_timestamp},
+ {"native_getMetrics", "()Landroid/os/PersistableBundle;",
+ (void *)android_media_AudioTrack_native_getMetrics},
{"native_set_loop", "(III)I", (void *)android_media_AudioTrack_set_loop},
{"native_reload_static", "()I", (void *)android_media_AudioTrack_reload},
{"native_get_output_sample_rate",
diff --git a/media/jni/android_media_MediaMetricsJNI.cpp b/core/jni/android_media_MediaMetricsJNI.cpp
similarity index 100%
rename from media/jni/android_media_MediaMetricsJNI.cpp
rename to core/jni/android_media_MediaMetricsJNI.cpp
diff --git a/media/jni/android_media_MediaMetricsJNI.h b/core/jni/android_media_MediaMetricsJNI.h
similarity index 100%
rename from media/jni/android_media_MediaMetricsJNI.h
rename to core/jni/android_media_MediaMetricsJNI.h
diff --git a/core/proto/android/app/activitymanager.proto b/core/proto/android/app/activitymanager.proto
index 03f8204..4756c13 100644
--- a/core/proto/android/app/activitymanager.proto
+++ b/core/proto/android/app/activitymanager.proto
@@ -21,65 +21,6 @@
option java_multiple_files = true;
option java_outer_classname = "ActivityManagerProto";
-// ActivityManager.java PROCESS_STATEs
-enum ProcessState {
- // Order matters for process states, so values have been spaced to provide
- // room for future additions.
-
- // Not a real process state.
- PROCESS_STATE_UNKNOWN = -100;
- // Process is a persistent system process.
- PROCESS_STATE_PERSISTENT = 0;
- // Process is a persistent system process and is doing UI.
- PROCESS_STATE_PERSISTENT_UI = 100;
- // Process is hosting the current top activities. Note that this covers
- // all activities that are visible to the user.
- PROCESS_STATE_TOP = 200;
- // Process is hosting a foreground service due to a system binding.
- PROCESS_STATE_BOUND_FOREGROUND_SERVICE = 300;
- // Process is hosting a foreground service.
- PROCESS_STATE_FOREGROUND_SERVICE = 400;
- // Process is important to the user, and something they are aware of.
- PROCESS_STATE_IMPORTANT_FOREGROUND = 500;
- // Process is important to the user, but not something they are aware of.
- PROCESS_STATE_IMPORTANT_BACKGROUND = 600;
- // Process is in the background transient so we will try to keep running.
- PROCESS_STATE_TRANSIENT_BACKGROUND = 700;
- // Process is in the background running a backup/restore operation.
- PROCESS_STATE_BACKUP = 800;
- // Process is in the background running a service. Unlike oom_adj, this
- // level is used for both the normal running in background state and the
- // executing operations state.
- PROCESS_STATE_SERVICE = 900;
- // Process is in the background running a receiver. Note that from the
- // perspective of oom_adj, receivers run at a higher foreground level, but
- // for our prioritization here that is not necessary and putting them
- // below services means many fewer changes in some process states as they
- // receive broadcasts.
- PROCESS_STATE_RECEIVER = 1000;
- // Same as PROCESS_STATE_TOP but while device is sleeping.
- PROCESS_STATE_TOP_SLEEPING = 1100;
- // Process is in the background, but it can't restore its state so we want
- // to try to avoid killing it.
- PROCESS_STATE_HEAVY_WEIGHT = 1200;
- // Process is in the background but hosts the home activity.
- PROCESS_STATE_HOME = 1300;
- // Process is in the background but hosts the last shown activity.
- PROCESS_STATE_LAST_ACTIVITY = 1400;
- // Process is being cached for later use and contains activities.
- PROCESS_STATE_CACHED_ACTIVITY = 1500;
- // Process is being cached for later use and is a client of another cached
- // process that contains activities.
- PROCESS_STATE_CACHED_ACTIVITY_CLIENT = 1600;
- // Process is being cached for later use and has an activity that corresponds
- // to an existing recent task.
- PROCESS_STATE_CACHED_RECENT = 1700;
- // Process is being cached for later use and is empty.
- PROCESS_STATE_CACHED_EMPTY = 1800;
- // Process does not exist.
- PROCESS_STATE_NONEXISTENT = 1900;
-}
-
// ActivityManager.java UID_OBSERVERs flags
enum UidObserverFlag {
// report changes in process state, original value is 1 << 0
diff --git a/core/proto/android/app/enums.proto b/core/proto/android/app/enums.proto
new file mode 100644
index 0000000..2de2574
--- /dev/null
+++ b/core/proto/android/app/enums.proto
@@ -0,0 +1,87 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+syntax = "proto2";
+
+package android.app;
+
+option java_outer_classname = "AppProtoEnums";
+option java_multiple_files = true;
+
+// ActivityManager.java PROCESS_STATEs
+enum ProcessStateEnum {
+ // Unlike the ActivityManager PROCESS_STATE values, the ordering and numerical values
+ // here are completely fixed and arbitrary. Order is irrelevant.
+ // No attempt need be made to keep them in sync.
+ // The values here must not be modified. Any new process states can be appended to the end.
+
+ // Process state that is unknown to this proto file (i.e. is not mapped
+ // by ActivityManager.processStateAmToProto()). Can only happen if there's a bug in the mapping.
+ PROCESS_STATE_UNKNOWN_TO_PROTO = 998;
+ // Not a real process state.
+ PROCESS_STATE_UNKNOWN = 999;
+ // Process is a persistent system process.
+ PROCESS_STATE_PERSISTENT = 1000;
+ // Process is a persistent system process and is doing UI.
+ PROCESS_STATE_PERSISTENT_UI = 1001;
+ // Process is hosting the current top activities. Note that this covers
+ // all activities that are visible to the user.
+ PROCESS_STATE_TOP = 1002;
+ // Process is hosting a foreground service.
+ PROCESS_STATE_FOREGROUND_SERVICE = 1003;
+ // Process is hosting a foreground service due to a system binding.
+ PROCESS_STATE_BOUND_FOREGROUND_SERVICE = 1004;
+ // Process is important to the user, and something they are aware of.
+ PROCESS_STATE_IMPORTANT_FOREGROUND = 1005;
+ // Process is important to the user, but not something they are aware of.
+ PROCESS_STATE_IMPORTANT_BACKGROUND = 1006;
+ // Process is in the background transient so we will try to keep running.
+ PROCESS_STATE_TRANSIENT_BACKGROUND = 1007;
+ // Process is in the background running a backup/restore operation.
+ PROCESS_STATE_BACKUP = 1008;
+ // Process is in the background running a service. Unlike oom_adj, this
+ // level is used for both the normal running in background state and the
+ // executing operations state.
+ PROCESS_STATE_SERVICE = 1009;
+ // Process is in the background running a receiver. Note that from the
+ // perspective of oom_adj, receivers run at a higher foreground level, but
+ // for our prioritization here that is not necessary and putting them
+ // below services means many fewer changes in some process states as they
+ // receive broadcasts.
+ PROCESS_STATE_RECEIVER = 1010;
+ // Same as PROCESS_STATE_TOP but while device is sleeping.
+ PROCESS_STATE_TOP_SLEEPING = 1011;
+ // Process is in the background, but it can't restore its state so we want
+ // to try to avoid killing it.
+ PROCESS_STATE_HEAVY_WEIGHT = 1012;
+ // Process is in the background but hosts the home activity.
+ PROCESS_STATE_HOME = 1013;
+ // Process is in the background but hosts the last shown activity.
+ PROCESS_STATE_LAST_ACTIVITY = 1014;
+ // Process is being cached for later use and contains activities.
+ PROCESS_STATE_CACHED_ACTIVITY = 1015;
+ // Process is being cached for later use and is a client of another cached
+ // process that contains activities.
+ PROCESS_STATE_CACHED_ACTIVITY_CLIENT = 1016;
+ // Process is being cached for later use and has an activity that corresponds
+ // to an existing recent task.
+ PROCESS_STATE_CACHED_RECENT = 1017;
+ // Process is being cached for later use and is empty.
+ PROCESS_STATE_CACHED_EMPTY = 1018;
+ // Process does not exist.
+ PROCESS_STATE_NONEXISTENT = 1019;
+}
+
diff --git a/core/proto/android/app/notification.proto b/core/proto/android/app/notification.proto
index 5376b0e..379a4ae 100644
--- a/core/proto/android/app/notification.proto
+++ b/core/proto/android/app/notification.proto
@@ -18,6 +18,8 @@
option java_package = "android.app";
option java_multiple_files = true;
+import "frameworks/base/libs/incident/proto/android/privacy.proto";
+
package android.app;
/**
@@ -25,13 +27,15 @@
* Deprecated fields are not included in the proto.
*/
message NotificationProto {
- optional string channel_id = 1;
+ option (.android.msg_privacy).dest = DEST_AUTOMATIC;
+
+ optional string channel_id = 1 [ (.android.privacy).dest = DEST_EXPLICIT ];
optional bool has_ticker_text = 2;
optional int32 flags = 3;
optional int32 color = 4;
- optional string category = 5;
- optional string group_key = 6;
- optional string sort_key = 7;
+ optional string category = 5 [ (.android.privacy).dest = DEST_EXPLICIT ];
+ optional string group_key = 6 [ (.android.privacy).dest = DEST_EXPLICIT ];
+ optional string sort_key = 7 [ (.android.privacy).dest = DEST_EXPLICIT ];
optional int32 action_length = 8;
// If this field is not set, then the value is unknown.
diff --git a/core/proto/android/app/profilerinfo.proto b/core/proto/android/app/profilerinfo.proto
index ca1b935..6b28318 100644
--- a/core/proto/android/app/profilerinfo.proto
+++ b/core/proto/android/app/profilerinfo.proto
@@ -18,12 +18,16 @@
option java_package = "android.app";
option java_multiple_files = true;
+import "frameworks/base/libs/incident/proto/android/privacy.proto";
+
package android.app;
/**
* An android.app.ProfilerInfo object.
*/
message ProfilerInfoProto {
+ option (.android.msg_privacy).dest = DEST_AUTOMATIC;
+
optional string profile_file = 1;
optional int32 profile_fd = 2;
optional int32 sampling_interval = 3;
diff --git a/core/proto/android/content/configuration.proto b/core/proto/android/content/configuration.proto
index 111b27f..a62d56c 100644
--- a/core/proto/android/content/configuration.proto
+++ b/core/proto/android/content/configuration.proto
@@ -22,11 +22,14 @@
import "frameworks/base/core/proto/android/app/window_configuration.proto";
import "frameworks/base/core/proto/android/content/locale.proto";
+import "frameworks/base/libs/incident/proto/android/privacy.proto";
/**
* An android resource configuration.
*/
message ConfigurationProto {
+ option (.android.msg_privacy).dest = DEST_AUTOMATIC;
+
optional float font_scale = 1;
optional uint32 mcc = 2;
optional uint32 mnc = 3;
diff --git a/core/proto/android/content/featureinfo.proto b/core/proto/android/content/featureinfo.proto
index a750120..6878f0e 100644
--- a/core/proto/android/content/featureinfo.proto
+++ b/core/proto/android/content/featureinfo.proto
@@ -16,14 +16,20 @@
syntax = "proto2";
+import "frameworks/base/libs/incident/proto/android/privacy.proto";
+
option java_package = "android.content.pm";
option java_multiple_files = true;
package android.content.pm;
message FeatureInfoProto {
+ option (android.msg_privacy).dest = DEST_AUTOMATIC;
+
+ // Some hard coded feature name
optional string name = 1;
optional int32 version = 2;
+ // String representation of reqGlEsVersion.
optional string gles_version = 3;
optional int32 flags = 4;
}
diff --git a/core/proto/android/content/intent.proto b/core/proto/android/content/intent.proto
index 3e5265a..c25b46d 100644
--- a/core/proto/android/content/intent.proto
+++ b/core/proto/android/content/intent.proto
@@ -21,9 +21,12 @@
option java_multiple_files = true;
import "frameworks/base/core/proto/android/os/patternmatcher.proto";
+import "frameworks/base/libs/incident/proto/android/privacy.proto";
// Next Tag: 13
message IntentProto {
+ option (.android.msg_privacy).dest = DEST_AUTOMATIC;
+
enum DockState {
// Used as an int value for Intent#EXTRA_DOCK_STATE to represent that
// the phone is not in any dock.
@@ -48,13 +51,13 @@
optional string action = 1;
repeated string categories = 2;
- optional string data = 3;
+ optional string data = 3 [ (.android.privacy).dest = DEST_EXPLICIT ];
optional string type = 4;
optional string flag = 5;
optional string package = 6;
optional string component = 7;
optional string source_bounds = 8;
- optional string clip_data = 9;
+ optional string clip_data = 9 [ (.android.privacy).dest = DEST_EXPLICIT ];
optional string extras = 10;
optional int32 content_user_hint = 11;
optional string selector = 12;
@@ -62,9 +65,11 @@
// Next Tag: 11
message IntentFilterProto {
+ option (.android.msg_privacy).dest = DEST_AUTOMATIC;
+
repeated string actions = 1;
repeated string categories = 2;
- repeated string data_schemes = 3;
+ repeated string data_schemes = 3 [ (.android.privacy).dest = DEST_EXPLICIT ];
repeated android.os.PatternMatcherProto data_scheme_specs = 4;
repeated AuthorityEntryProto data_authorities = 5;
repeated android.os.PatternMatcherProto data_paths = 6;
@@ -75,6 +80,8 @@
}
message AuthorityEntryProto {
+ option (.android.msg_privacy).dest = DEST_AUTOMATIC;
+
optional string host = 1;
optional bool wild = 2;
optional int32 port = 3;
diff --git a/core/proto/android/content/locale.proto b/core/proto/android/content/locale.proto
index f0de31c..2be3ab9 100644
--- a/core/proto/android/content/locale.proto
+++ b/core/proto/android/content/locale.proto
@@ -18,9 +18,13 @@
option java_package = "android.content";
option java_multiple_files = true;
+import "frameworks/base/libs/incident/proto/android/privacy.proto";
+
package android.content;
message LocaleProto {
+ option (.android.msg_privacy).dest = DEST_AUTOMATIC;
+
optional string language = 1;
optional string country = 2;
optional string variant = 3;
diff --git a/core/proto/android/content/package_item_info.proto b/core/proto/android/content/package_item_info.proto
index 8470159..6e99bec 100644
--- a/core/proto/android/content/package_item_info.proto
+++ b/core/proto/android/content/package_item_info.proto
@@ -18,9 +18,13 @@
option java_package = "android.content.pm";
option java_multiple_files = true;
+import "frameworks/base/libs/incident/proto/android/privacy.proto";
+
package android.content.pm;
message PackageItemInfoProto {
+ option (.android.msg_privacy).dest = DEST_AUTOMATIC;
+
optional string name = 1;
optional string package_name = 2;
optional int32 label_res = 3;
@@ -31,6 +35,8 @@
// Proto of android.content.pm.ApplicationInfo which extends PackageItemInfo
message ApplicationInfoProto {
+ option (.android.msg_privacy).dest = DEST_AUTOMATIC;
+
optional PackageItemInfoProto package = 1;
optional string permission = 2;
optional string process_name = 3;
@@ -48,6 +54,8 @@
repeated string split_class_loader_names = 15;
message Version {
+ option (.android.msg_privacy).dest = DEST_AUTOMATIC;
+
optional bool enabled = 1;
optional int32 min_sdk_version = 2;
optional int32 target_sdk_version = 3;
@@ -57,6 +65,8 @@
optional Version version = 16;
message Detail {
+ option (.android.msg_privacy).dest = DEST_EXPLICIT;
+
optional string class_name = 1;
optional string task_affinity = 2;
optional int32 requires_smallest_width_dp = 3;
diff --git a/core/proto/android/graphics/point.proto b/core/proto/android/graphics/point.proto
index 5ae17cb..035b9fe 100644
--- a/core/proto/android/graphics/point.proto
+++ b/core/proto/android/graphics/point.proto
@@ -17,9 +17,13 @@
syntax = "proto2";
package android.graphics;
+import "frameworks/base/libs/incident/proto/android/privacy.proto";
+
option java_multiple_files = true;
message PointProto {
+ option (.android.msg_privacy).dest = DEST_AUTOMATIC;
+
optional int32 x = 1;
optional int32 y = 2;
}
diff --git a/core/proto/android/graphics/rect.proto b/core/proto/android/graphics/rect.proto
index 562ffce..eb403fe 100644
--- a/core/proto/android/graphics/rect.proto
+++ b/core/proto/android/graphics/rect.proto
@@ -17,9 +17,13 @@
syntax = "proto2";
package android.graphics;
+import "frameworks/base/libs/incident/proto/android/privacy.proto";
+
option java_multiple_files = true;
message RectProto {
+ option (android.msg_privacy).dest = DEST_AUTOMATIC;
+
optional int32 left = 1;
optional int32 top = 2;
optional int32 right = 3;
diff --git a/core/proto/android/os/cpufreq.proto b/core/proto/android/os/cpufreq.proto
index a8da0bf..8481ffc 100644
--- a/core/proto/android/os/cpufreq.proto
+++ b/core/proto/android/os/cpufreq.proto
@@ -18,10 +18,13 @@
option java_multiple_files = true;
option java_outer_classname = "CpuFreqProto";
+import "frameworks/base/libs/incident/proto/android/privacy.proto";
+
package android.os;
// cpu frequency time from /sys/devices/system/cpu/cpufreq/all_time_in_state
message CpuFreq {
+ option (android.msg_privacy).dest = DEST_AUTOMATIC;
optional int32 jiffy_hz = 1; // obtain by system config.
@@ -30,10 +33,13 @@
// frequency time pre cpu, unit in jiffy, TODO: obtain jiffies.
message CpuFreqStats {
+ option (android.msg_privacy).dest = DEST_AUTOMATIC;
optional string cpu_name = 1;
message TimeInState {
+ option (android.msg_privacy).dest = DEST_AUTOMATIC;
+
optional int32 state_khz = 1; // cpu frequency
optional int64 time_jiffy = 2; // number of jiffies
}
diff --git a/core/proto/android/os/cpuinfo.proto b/core/proto/android/os/cpuinfo.proto
index cd151e2..ca43602 100644
--- a/core/proto/android/os/cpuinfo.proto
+++ b/core/proto/android/os/cpuinfo.proto
@@ -18,6 +18,8 @@
option java_multiple_files = true;
option java_outer_classname = "CpuInfoProto";
+import "frameworks/base/libs/incident/proto/android/privacy.proto";
+
package android.os;
/**
@@ -27,8 +29,11 @@
* Next Tag: 6
*/
message CpuInfo {
+ option (android.msg_privacy).dest = DEST_AUTOMATIC;
message TaskStats {
+ option (android.msg_privacy).dest = DEST_AUTOMATIC;
+
optional int32 total = 1; // total number of cpu tasks
optional int32 running = 2; // number of running tasks
optional int32 sleeping = 3; // number of sleeping tasks
@@ -38,6 +43,8 @@
optional TaskStats task_stats = 1;
message MemStats { // unit in kB
+ option (android.msg_privacy).dest = DEST_AUTOMATIC;
+
optional int32 total = 1;
optional int32 used = 2;
optional int32 free = 3;
@@ -48,6 +55,8 @@
optional MemStats swap = 3;
message CpuUsage { // unit is percentage %
+ option (android.msg_privacy).dest = DEST_AUTOMATIC;
+
optional int32 cpu = 1; // 400% cpu indicates 4 cores
optional int32 user = 2;
optional int32 nice = 3;
@@ -62,9 +71,11 @@
// Next Tag: 13
message Task {
+ option (android.msg_privacy).dest = DEST_AUTOMATIC;
+
optional int32 pid = 1;
optional int32 tid = 2;
- optional string user = 3;
+ optional string user = 3; // the process name which uses cpu
optional string pr = 4; // priority of each task, using string type is because special value RT (real time)
optional sint32 ni = 5; // niceness value
optional float cpu = 6; // precentage of cpu usage of the task
diff --git a/core/proto/android/os/kernelwake.proto b/core/proto/android/os/kernelwake.proto
index 7e5be9d..c296dab 100644
--- a/core/proto/android/os/kernelwake.proto
+++ b/core/proto/android/os/kernelwake.proto
@@ -18,15 +18,21 @@
option java_multiple_files = true;
option java_outer_classname = "WakeupSourcesProto";
+import "frameworks/base/libs/incident/proto/android/privacy.proto";
+
package android.os;
message KernelWakeSources {
+ option (android.msg_privacy).dest = DEST_AUTOMATIC;
+
// Kernel records of what caused the application processor to wake up
repeated WakeupSourceProto wakeup_sources = 1;
}
// Next Tag: 11
message WakeupSourceProto {
+ option (android.msg_privacy).dest = DEST_AUTOMATIC;
+
// Name of the event which triggers application processor
optional string name = 1;
diff --git a/core/proto/android/os/looper.proto b/core/proto/android/os/looper.proto
index ef84bb1..435c648 100644
--- a/core/proto/android/os/looper.proto
+++ b/core/proto/android/os/looper.proto
@@ -20,9 +20,12 @@
option java_multiple_files = true;
import "frameworks/base/core/proto/android/os/messagequeue.proto";
+import "frameworks/base/libs/incident/proto/android/privacy.proto";
message LooperProto {
- optional string thread_name = 1;
+ option (.android.msg_privacy).dest = DEST_AUTOMATIC;
+
+ optional string thread_name = 1 [ (.android.privacy).dest = DEST_EXPLICIT ];
optional int64 thread_id = 2;
optional int32 identity_hash_code = 3;
optional android.os.MessageQueueProto queue = 4;
diff --git a/core/proto/android/os/message.proto b/core/proto/android/os/message.proto
index 38e27a1..048d031 100644
--- a/core/proto/android/os/message.proto
+++ b/core/proto/android/os/message.proto
@@ -17,9 +17,12 @@
syntax = "proto2";
package android.os;
+import "frameworks/base/libs/incident/proto/android/privacy.proto";
option java_multiple_files = true;
message MessageProto {
+ option (.android.msg_privacy).dest = DEST_AUTOMATIC;
+
optional int64 when = 1;
// Name of callback class.
optional string callback = 2;
@@ -29,7 +32,7 @@
optional int32 arg1 = 4;
optional int32 arg2 = 5;
// String representation of an arbitrary object to send to the recipient.
- optional string obj = 6;
+ optional string obj = 6 [ (.android.privacy).dest = DEST_EXPLICIT ];
// Name of target class.
optional string target = 7;
optional int32 barrier = 8;
diff --git a/core/proto/android/os/messagequeue.proto b/core/proto/android/os/messagequeue.proto
index 5d4bff0..4bfcb81 100644
--- a/core/proto/android/os/messagequeue.proto
+++ b/core/proto/android/os/messagequeue.proto
@@ -20,8 +20,11 @@
option java_multiple_files = true;
import "frameworks/base/core/proto/android/os/message.proto";
+import "frameworks/base/libs/incident/proto/android/privacy.proto";
message MessageQueueProto {
+ option (.android.msg_privacy).dest = DEST_AUTOMATIC;
+
repeated android.os.MessageProto messages = 1;
optional bool is_polling_locked = 2;
optional bool is_quitting = 3;
diff --git a/core/proto/android/os/pagetypeinfo.proto b/core/proto/android/os/pagetypeinfo.proto
index f82ea76..b8f618b 100644
--- a/core/proto/android/os/pagetypeinfo.proto
+++ b/core/proto/android/os/pagetypeinfo.proto
@@ -18,6 +18,8 @@
option java_multiple_files = true;
option java_outer_classname = "PageTypeInfoProto";
+import "frameworks/base/libs/incident/proto/android/privacy.proto";
+
package android.os;
/*
@@ -36,6 +38,7 @@
* Next tag: 5
*/
message PageTypeInfo {
+ option (android.msg_privacy).dest = DEST_AUTOMATIC;
optional int32 page_block_order = 1;
@@ -48,6 +51,7 @@
// Next tag: 5
message MigrateTypeProto {
+ option (android.msg_privacy).dest = DEST_AUTOMATIC;
optional int32 node = 1;
@@ -61,6 +65,7 @@
// Next tag: 9
message BlockProto {
+ option (android.msg_privacy).dest = DEST_AUTOMATIC;
optional int32 node = 1;
diff --git a/core/proto/android/os/patternmatcher.proto b/core/proto/android/os/patternmatcher.proto
index d30315b..520f2f5 100644
--- a/core/proto/android/os/patternmatcher.proto
+++ b/core/proto/android/os/patternmatcher.proto
@@ -16,10 +16,13 @@
syntax = "proto2";
option java_multiple_files = true;
+import "frameworks/base/libs/incident/proto/android/privacy.proto";
package android.os;
message PatternMatcherProto {
+ option (android.msg_privacy).dest = DEST_EXPLICIT;
+
optional string pattern = 1;
enum Type {
diff --git a/core/proto/android/os/system_properties.proto b/core/proto/android/os/system_properties.proto
index 07b9ad0..694b94b 100644
--- a/core/proto/android/os/system_properties.proto
+++ b/core/proto/android/os/system_properties.proto
@@ -134,6 +134,8 @@
optional bool hal_instrumentation_enable = 11;
message InitSvc {
+ option (android.msg_privacy).dest = DEST_AUTOMATIC;
+
enum Status {
STATUS_UNKNOWN = 0;
STATUS_RUNNING = 1;
@@ -230,7 +232,7 @@
// Read only properites on the device.
message Ro {
- optional bool adb_secure = 1;
+ optional bool adb_secure = 1 [ (android.privacy).dest = DEST_AUTOMATIC ];
optional string arch = 2;
optional bool audio_ignore_effects = 3;
optional bool audio_monitorRotation = 4;
@@ -265,6 +267,8 @@
// boot.img's properties.
message BootImage {
+ option (android.msg_privacy).dest = DEST_AUTOMATIC;
+
// When the boot.img is built.
optional string build_date = 1;
// UTC timestamp of build date.
@@ -278,12 +282,14 @@
optional BootImage bootimage = 8;
// Version of bootloader on device.
- optional string bootloader = 9;
+ optional string bootloader = 9 [ (android.privacy).dest = DEST_AUTOMATIC ];
// Kernel bootmode, e.g. charger.
- optional string bootmode = 10;
+ optional string bootmode = 10 [ (android.privacy).dest = DEST_AUTOMATIC ];
// Android Platform build metadata.
message Build {
+ option (android.msg_privacy).dest = DEST_AUTOMATIC;
+
optional string date = 1;
optional int64 date_utc = 2;
optional string description = 3;
@@ -297,6 +303,8 @@
optional string user = 11;
message Version {
+ option (android.msg_privacy).dest = DEST_AUTOMATIC;
+
optional string base_os = 1;
optional string codename = 2;
optional string incremental = 3;
@@ -313,10 +321,10 @@
}
optional Build build = 11;
- optional bool camera_notify_nfc = 12;
+ optional bool camera_notify_nfc = 12 [ (android.privacy).dest = DEST_AUTOMATIC ];
optional string carrier = 13;
- optional bool com_android_dataroaming = 14;
- optional bool com_android_prov_mobiledata = 15;
+ optional bool com_android_dataroaming = 14 [ (android.privacy).dest = DEST_AUTOMATIC ];
+ optional bool com_android_prov_mobiledata = 15 [ (android.privacy).dest = DEST_AUTOMATIC ];
optional string com_google_clientidbase = 16;
message Config {
@@ -341,6 +349,8 @@
optional string gfx_driver_0 = 26;
message Hardware {
+ option (android.msg_privacy).dest = DEST_LOCAL;
+
optional string value = 1; // value of ro.hardware itself
optional string activity_recognition = 2;
@@ -392,6 +402,8 @@
optional int32 opengles_version = 31;
message Product {
+ option (android.msg_privacy).dest = DEST_AUTOMATIC;
+
optional string board = 1;
optional string brand = 2;
optional string cpu_abi = 3;
@@ -405,6 +417,8 @@
optional string name = 11;
message Vendor {
+ option (android.msg_privacy).dest = DEST_AUTOMATIC;
+
optional string brand = 1;
optional string device = 2;
optional string manufacturer = 3;
diff --git a/core/proto/android/server/activitymanagerservice.proto b/core/proto/android/server/activitymanagerservice.proto
index 1434d82..55e6a74 100644
--- a/core/proto/android/server/activitymanagerservice.proto
+++ b/core/proto/android/server/activitymanagerservice.proto
@@ -19,6 +19,7 @@
package com.android.server.am.proto;
import "frameworks/base/core/proto/android/app/activitymanager.proto";
+import "frameworks/base/core/proto/android/app/enums.proto";
import "frameworks/base/core/proto/android/app/notification.proto";
import "frameworks/base/core/proto/android/app/profilerinfo.proto";
import "frameworks/base/core/proto/android/content/component_name.proto";
@@ -32,10 +33,13 @@
import "frameworks/base/core/proto/android/server/intentresolver.proto";
import "frameworks/base/core/proto/android/server/windowmanagerservice.proto";
import "frameworks/base/core/proto/android/util/common.proto";
+import "frameworks/base/libs/incident/proto/android/privacy.proto";
option java_multiple_files = true;
message ActivityManagerServiceProto {
+ option (.android.msg_privacy).dest = DEST_AUTOMATIC;
+
optional ActivityStackSupervisorProto activities = 1;
optional BroadcastProto broadcasts = 2;
@@ -47,6 +51,8 @@
// "dumpsys activity --proto activities"
message ActivityStackSupervisorProto {
+ option (.android.msg_privacy).dest = DEST_AUTOMATIC;
+
optional .com.android.server.wm.proto.ConfigurationContainerProto configuration_container = 1;
repeated ActivityDisplayProto displays = 2;
optional KeyguardControllerProto keyguard_controller = 3;
@@ -56,12 +62,16 @@
/* represents ActivityStackSupervisor.ActivityDisplay */
message ActivityDisplayProto {
+ option (.android.msg_privacy).dest = DEST_AUTOMATIC;
+
optional .com.android.server.wm.proto.ConfigurationContainerProto configuration_container = 1;
optional int32 id = 2;
repeated ActivityStackProto stacks = 3;
}
message ActivityStackProto {
+ option (.android.msg_privacy).dest = DEST_AUTOMATIC;
+
optional .com.android.server.wm.proto.ConfigurationContainerProto configuration_container = 1;
optional int32 id = 2;
repeated TaskRecordProto tasks = 3;
@@ -72,6 +82,8 @@
}
message TaskRecordProto {
+ option (.android.msg_privacy).dest = DEST_AUTOMATIC;
+
optional .com.android.server.wm.proto.ConfigurationContainerProto configuration_container = 1;
optional int32 id = 2;
repeated ActivityRecordProto activities = 3;
@@ -88,6 +100,8 @@
}
message ActivityRecordProto {
+ option (.android.msg_privacy).dest = DEST_AUTOMATIC;
+
optional .com.android.server.wm.proto.ConfigurationContainerProto configuration_container = 1;
optional .com.android.server.wm.proto.IdentifierProto identifier = 2;
optional string state = 3;
@@ -97,12 +111,16 @@
}
message KeyguardControllerProto {
+ option (.android.msg_privacy).dest = DEST_AUTOMATIC;
+
optional bool keyguard_showing = 1;
optional bool keyguard_occluded = 2;
}
// "dumpsys activity --proto broadcasts"
message BroadcastProto {
+ option (.android.msg_privacy).dest = DEST_AUTOMATIC;
+
repeated ReceiverListProto receiver_list = 1;
optional .com.android.server.IntentResolverProto receiver_resolver = 2;
@@ -119,6 +137,8 @@
}
message ReceiverListProto {
+ option (.android.msg_privacy).dest = DEST_AUTOMATIC;
+
optional ProcessRecordProto app = 1;
optional int32 pid = 2;
optional int32 uid = 3;
@@ -130,6 +150,8 @@
}
message ProcessRecordProto {
+ option (.android.msg_privacy).dest = DEST_AUTOMATIC;
+
optional int32 pid = 1;
optional string process_name = 2;
optional int32 uid = 3;
@@ -140,11 +162,15 @@
}
message BroadcastRecordProto {
+ option (.android.msg_privacy).dest = DEST_AUTOMATIC;
+
optional int32 user_id = 1;
optional string intent_action = 2;
}
message BroadcastFilterProto {
+ option (.android.msg_privacy).dest = DEST_AUTOMATIC;
+
optional .android.content.IntentFilterProto intent_filter = 1;
optional string required_permission = 2;
optional string hex_hash = 3; // used to find the object in IntentResolver
@@ -152,6 +178,8 @@
}
message BroadcastQueueProto {
+ option (.android.msg_privacy).dest = DEST_AUTOMATIC;
+
optional string queue_name = 1;
repeated BroadcastRecordProto parallel_broadcasts = 2;
repeated BroadcastRecordProto ordered_broadcasts = 3;
@@ -159,6 +187,8 @@
repeated BroadcastRecordProto historical_broadcasts = 5;
message BroadcastSummary {
+ option (.android.msg_privacy).dest = DEST_AUTOMATIC;
+
optional .android.content.IntentProto intent = 1;
optional int64 enqueue_clock_time_ms = 2;
optional int64 dispatch_clock_time_ms = 3;
@@ -168,14 +198,20 @@
}
message MemInfoProto {
+ option (.android.msg_privacy).dest = DEST_AUTOMATIC;
+
optional int64 uptime_duration_ms = 1;
optional int64 elapsed_realtime_ms = 2;
message ProcessMemory {
+ option (.android.msg_privacy).dest = DEST_AUTOMATIC;
+
optional int32 pid = 1;
optional string process_name = 2;
message MemoryInfo {
+ option (.android.msg_privacy).dest = DEST_AUTOMATIC;
+
optional string name = 1;
// The proportional set size for the heap.
optional int32 total_pss_kb = 2;
@@ -197,6 +233,8 @@
}
}
message HeapInfo {
+ option (.android.msg_privacy).dest = DEST_AUTOMATIC;
+
optional MemoryInfo mem_info = 1;
optional int32 heap_size_kb = 2;
optional int32 heap_alloc_kb = 3;
@@ -212,6 +250,8 @@
repeated MemoryInfo dalvik_details = 8;
message AppSummary {
+ option (.android.msg_privacy).dest = DEST_AUTOMATIC;
+
optional int32 java_heap_pss_kb = 1;
optional int32 native_heap_pss_kb = 2;
optional int32 code_pss_kb = 3;
@@ -230,9 +270,13 @@
repeated ProcessMemory native_processes = 3;
message AppData {
+ option (.android.msg_privacy).dest = DEST_AUTOMATIC;
+
optional ProcessMemory process_memory = 1;
message ObjectStats {
+ option (.android.msg_privacy).dest = DEST_AUTOMATIC;
+
optional int32 view_instance_count = 1;
optional int32 view_root_instance_count = 2;
optional int32 app_context_instance_count = 3;
@@ -250,11 +294,15 @@
optional ObjectStats objects = 2;
message SqlStats {
+ option (.android.msg_privacy).dest = DEST_AUTOMATIC;
+
optional int32 memory_used_kb = 1;
optional int32 pagecache_overflow_kb = 2;
optional int32 malloc_size_kb = 3;
message Database {
+ option (.android.msg_privacy).dest = DEST_AUTOMATIC;
+
optional string name = 1;
optional int32 page_size = 2;
optional int32 db_size = 3;
@@ -274,6 +322,8 @@
repeated AppData app_processes = 4;
message MemItem {
+ option (.android.msg_privacy).dest = DEST_AUTOMATIC;
+
optional string tag = 1;
optional string label = 2;
optional int32 id = 3;
@@ -337,9 +387,13 @@
}
message StickyBroadcastProto {
+ option (.android.msg_privacy).dest = DEST_AUTOMATIC;
+
optional int32 user = 1;
message StickyAction {
+ option (.android.msg_privacy).dest = DEST_AUTOMATIC;
+
optional string name = 1;
repeated .android.content.IntentProto intents = 2;
}
@@ -348,6 +402,7 @@
// "dumpsys activity --proto service"
message ActiveServicesProto {
+ option (.android.msg_privacy).dest = DEST_AUTOMATIC;
message ServicesByUser {
optional int32 user_id = 1;
@@ -358,11 +413,15 @@
// corresponds to ActivityManagerService.GrantUri Java class
message GrantUriProto {
+ option (.android.msg_privacy).dest = DEST_AUTOMATIC;
+
optional int32 source_user_id = 1;
- optional string uri = 2;
+ optional string uri = 2 [ (.android.privacy).dest = DEST_EXPLICIT ];
}
message NeededUriGrantsProto {
+ option (.android.msg_privacy).dest = DEST_AUTOMATIC;
+
optional string target_package = 1;
optional int32 target_uid = 2;
optional int32 flags = 3;
@@ -371,12 +430,16 @@
}
message UriPermissionOwnerProto {
+ option (.android.msg_privacy).dest = DEST_EXPLICIT;
+
optional string owner = 1;
repeated GrantUriProto read_perms = 2;
repeated GrantUriProto write_perms = 3;
}
message ServiceRecordProto {
+ option (.android.msg_privacy).dest = DEST_AUTOMATIC;
+
optional string short_name = 1;
optional string hex_hash = 2;
optional bool is_running = 3; // false if the application service is null
@@ -387,6 +450,8 @@
optional string permission = 8;
message AppInfo {
+ option (.android.msg_privacy).dest = DEST_EXPLICIT;
+
optional string base_dir = 1;
optional string res_dir = 2;
optional string data_dir = 3;
@@ -398,6 +463,8 @@
optional bool delayed = 13;
message Foreground {
+ option (.android.msg_privacy).dest = DEST_AUTOMATIC;
+
optional int32 id = 1;
optional .android.app.NotificationProto notification = 2;
}
@@ -411,6 +478,8 @@
// variables used to track states related to service start
message Start {
+ option (.android.msg_privacy).dest = DEST_AUTOMATIC;
+
optional bool start_requested = 1;
optional bool delayed_stop = 2;
optional bool stop_if_killed = 3;
@@ -420,6 +489,8 @@
optional Start start = 20;
message ExecuteNesting {
+ option (.android.msg_privacy).dest = DEST_AUTOMATIC;
+
optional int32 execute_nesting = 1;
optional bool execute_fg = 2;
optional .android.util.Duration executing_start = 3;
@@ -429,6 +500,8 @@
optional .android.util.Duration destory_time = 22;
message Crash {
+ option (.android.msg_privacy).dest = DEST_AUTOMATIC;
+
optional int32 restart_count = 1;
optional .android.util.Duration restart_delay = 2;
optional .android.util.Duration next_restart_time = 3;
@@ -437,6 +510,8 @@
optional Crash crash = 23;
message StartItemProto {
+ option (.android.msg_privacy).dest = DEST_AUTOMATIC;
+
optional int32 id = 1;
optional .android.util.Duration duration = 2;
optional int32 delivery_count = 3;
@@ -453,6 +528,8 @@
}
message ConnectionRecordProto {
+ option (.android.msg_privacy).dest = DEST_AUTOMATIC;
+
optional string hex_hash = 1;
optional int32 user_id = 2;
@@ -480,12 +557,16 @@
}
message AppBindRecordProto {
+ option (.android.msg_privacy).dest = DEST_AUTOMATIC;
+
optional string hex_hash = 1;
optional ProcessRecordProto client = 2;
repeated ConnectionRecordProto connections = 3;
}
message IntentBindRecordProto {
+ option (.android.msg_privacy).dest = DEST_AUTOMATIC;
+
optional string hex_hash = 1;
optional bool is_create = 2;
optional .android.content.IntentProto intent = 3;
@@ -500,6 +581,8 @@
// TODO: "dumpsys activity --proto processes"
message ProcessesProto {
+ option (.android.msg_privacy).dest = DEST_AUTOMATIC;
+
repeated ProcessRecordProto procs = 1;
repeated ProcessRecordProto isolated_procs = 2;
repeated ActiveInstrumentationProto active_instrumentations = 3;
@@ -508,6 +591,8 @@
// Process LRU list (sorted by oom_adj)
message LruProcesses {
+ option (.android.msg_privacy).dest = DEST_AUTOMATIC;
+
optional int32 size = 1;
optional int32 non_act_at = 2;
optional int32 non_svc_at = 3;
@@ -538,18 +623,24 @@
optional bool config_will_change = 21;
message ScreenCompatPackage {
+ option (.android.msg_privacy).dest = DEST_AUTOMATIC;
+
optional string package = 1;
optional int32 mode = 2;
}
repeated ScreenCompatPackage screen_compat_packages = 22;
message UidObserverRegistrationProto {
+ option (.android.msg_privacy).dest = DEST_AUTOMATIC;
+
optional int32 uid = 1;
optional string package = 2;
repeated .android.app.UidObserverFlag flags = 3;
optional int32 cut_point = 4; // only available when UID_OBSERVER_PROCSTATE is on
message ProcState {
+ option (.android.msg_privacy).dest = DEST_AUTOMATIC;
+
optional int32 uid = 1;
optional int32 state = 2;
}
@@ -560,6 +651,8 @@
repeated int32 device_idle_temp_whitelist = 25;
message PendingTempWhitelist {
+ option (.android.msg_privacy).dest = DEST_AUTOMATIC;
+
optional int32 target_uid = 1;
optional int64 duration_ms = 2;
optional string tag = 3;
@@ -567,6 +660,8 @@
repeated PendingTempWhitelist pending_temp_whitelist = 26;
message SleepStatus {
+ option (.android.msg_privacy).dest = DEST_AUTOMATIC;
+
optional .android.os.PowerManagerInternalProto.Wakefulness wakefulness = 1;
repeated string sleep_tokens = 2;
optional bool sleeping = 3;
@@ -576,12 +671,16 @@
optional SleepStatus sleep_status = 27;
message VoiceProto {
+ option (.android.msg_privacy).dest = DEST_AUTOMATIC;
+
optional string session = 1;
optional .android.os.PowerManagerProto.WakeLockProto wakelock = 2;
}
optional VoiceProto running_voice = 28;
message VrControllerProto {
+ option (.android.msg_privacy).dest = DEST_AUTOMATIC;
+
enum VrMode {
FLAG_NON_VR_MODE = 0;
FLAG_VR_MODE = 1;
@@ -593,6 +692,8 @@
optional VrControllerProto vr_controller = 29;
message DebugApp {
+ option (.android.msg_privacy).dest = DEST_AUTOMATIC;
+
optional string debug_app = 1;
optional string orig_debug_app = 2;
optional bool debug_transient = 3;
@@ -602,10 +703,16 @@
optional AppTimeTrackerProto current_tracker = 31;
message MemWatchProcess {
+ option (.android.msg_privacy).dest = DEST_AUTOMATIC;
+
message Process {
+ option (.android.msg_privacy).dest = DEST_AUTOMATIC;
+
optional string name = 1;
message MemStats {
+ option (.android.msg_privacy).dest = DEST_AUTOMATIC;
+
optional int32 uid = 1;
optional string size = 2;
optional string report_to = 3;
@@ -615,8 +722,10 @@
repeated Process procs = 1;
message Dump {
+ option (.android.msg_privacy).dest = DEST_AUTOMATIC;
+
optional string proc_name = 1;
- optional string file = 2;
+ optional string file = 2 [ (.android.privacy).dest = DEST_EXPLICIT ];
optional int32 pid = 3;
optional int32 uid = 4;
}
@@ -626,6 +735,8 @@
optional string track_allocation_app = 33;
message Profile {
+ option (.android.msg_privacy).dest = DEST_AUTOMATIC;
+
optional string app_name = 1;
optional ProcessRecordProto proc = 2;
optional .android.app.ProfilerInfoProto info = 3;
@@ -636,6 +747,8 @@
optional bool always_finish_activities = 36;
message Controller {
+ option (.android.msg_privacy).dest = DEST_AUTOMATIC;
+
optional string controller = 1;
optional bool is_a_monkey = 2;
}
@@ -666,6 +779,8 @@
}
message ActiveInstrumentationProto {
+ option (.android.msg_privacy).dest = DEST_AUTOMATIC;
+
optional .android.content.ComponentNameProto class = 1;
optional bool finished = 2;
repeated ProcessRecordProto running_processes = 3;
@@ -674,14 +789,16 @@
optional string profile_file = 6;
optional string watcher = 7;
optional string ui_automation_connection = 8;
- optional string arguments = 9;
+ optional string arguments = 9 [ (.android.privacy).dest = DEST_EXPLICIT ];
}
// Proto definition of com.android.server.am.UidRecord.java
message UidRecordProto {
+ option (.android.msg_privacy).dest = DEST_AUTOMATIC;
+
optional string hex_hash = 1;
optional int32 uid = 2;
- optional .android.app.ProcessState current = 3;
+ optional .android.app.ProcessStateEnum current = 3;
optional bool ephemeral = 4;
optional bool fg_services = 5;
optional bool whilelist = 6;
@@ -699,6 +816,8 @@
optional int32 num_procs = 10;
message ProcStateSequence {
+ option (.android.msg_privacy).dest = DEST_AUTOMATIC;
+
optional int64 cururent = 1;
optional int64 last_network_updated = 2;
optional int64 last_dispatched = 3;
@@ -708,12 +827,16 @@
// proto of class ImportanceToken in ActivityManagerService
message ImportanceTokenProto {
+ option (.android.msg_privacy).dest = DEST_EXPLICIT;
+
optional int32 pid = 1;
optional string token = 2;
optional string reason = 3;
}
message ProcessOomProto {
+ option (.android.msg_privacy).dest = DEST_AUTOMATIC;
+
optional bool persistent = 1;
optional int32 num = 2;
optional string oom_adj = 3;
@@ -733,7 +856,7 @@
bool services = 6;
}
- optional .android.app.ProcessState state = 7;
+ optional .android.app.ProcessStateEnum state = 7;
optional int32 trim_memory_level = 8;
optional ProcessRecordProto proc = 9;
optional string adj_type = 10;
@@ -749,13 +872,15 @@
}
message Detail {
+ option (.android.msg_privacy).dest = DEST_AUTOMATIC;
+
optional int32 max_adj = 1;
optional int32 cur_raw_adj = 2;
optional int32 set_raw_adj = 3;
optional int32 cur_adj = 4;
optional int32 set_adj = 5;
- optional .android.app.ProcessState current_state = 7;
- optional .android.app.ProcessState set_state = 8;
+ optional .android.app.ProcessStateEnum current_state = 7;
+ optional .android.app.ProcessStateEnum set_state = 8;
optional string last_pss = 9;
optional string last_swap_pss = 10;
optional string last_cached_pss = 11;
@@ -765,6 +890,8 @@
// only make sense if process is a service
message CpuRunTime {
+ option (.android.msg_privacy).dest = DEST_AUTOMATIC;
+
optional int64 over_ms = 1;
optional int64 used_ms = 2;
optional float ultilization = 3; // ratio of cpu time usage
@@ -775,6 +902,8 @@
}
message ProcessToGcProto {
+ option (.android.msg_privacy).dest = DEST_AUTOMATIC;
+
optional ProcessRecordProto proc = 1;
optional bool report_low_memory = 2;
optional int64 now_uptime_ms = 3;
@@ -784,13 +913,18 @@
// sync with com.android.server.am.AppErrors.java
message AppErrorsProto {
+ option (.android.msg_privacy).dest = DEST_AUTOMATIC;
optional int64 now_uptime_ms = 1;
message ProcessCrashTime {
+ option (.android.msg_privacy).dest = DEST_AUTOMATIC;
+
optional string process_name = 1;
message Entry {
+ option (.android.msg_privacy).dest = DEST_AUTOMATIC;
+
optional int32 uid = 1;
optional int64 last_crashed_at_ms = 2;
}
@@ -799,14 +933,18 @@
repeated ProcessCrashTime process_crash_times = 2;
message BadProcess {
+ option (.android.msg_privacy).dest = DEST_AUTOMATIC;
+
optional string process_name = 1;
message Entry {
+ option (.android.msg_privacy).dest = DEST_AUTOMATIC;
+
optional int32 uid = 1;
optional int64 crashed_at_ms = 2;
optional string short_msg = 3;
- optional string long_msg = 4;
- optional string stack = 5;
+ optional string long_msg = 4 [ (.android.privacy).dest = DEST_EXPLICIT ];
+ optional string stack = 5 [ (.android.privacy).dest = DEST_EXPLICIT ];
}
repeated Entry entries = 2;
}
@@ -815,6 +953,8 @@
// sync with com.android.server.am.UserState.java
message UserStateProto {
+ option (.android.msg_privacy).dest = DEST_AUTOMATIC;
+
enum State {
STATE_BOOTING = 0;
STATE_RUNNING_LOCKED = 1;
@@ -829,7 +969,11 @@
// sync with com.android.server.am.UserController.java
message UserControllerProto {
+ option (.android.msg_privacy).dest = DEST_AUTOMATIC;
+
message User {
+ option (.android.msg_privacy).dest = DEST_AUTOMATIC;
+
optional int32 id = 1;
optional UserStateProto state = 2;
}
@@ -838,6 +982,8 @@
repeated int32 user_lru = 3;
message UserProfile {
+ option (.android.msg_privacy).dest = DEST_AUTOMATIC;
+
optional int32 user = 1;
optional int32 profile = 2;
}
@@ -846,6 +992,8 @@
// sync with com.android.server.am.AppTimeTracker.java
message AppTimeTrackerProto {
+ option (.android.msg_privacy).dest = DEST_AUTOMATIC;
+
optional string receiver = 1;
optional int64 total_duration_ms = 2;
diff --git a/core/proto/android/server/appwindowthumbnail.proto b/core/proto/android/server/appwindowthumbnail.proto
index e67b854..8f48d75 100644
--- a/core/proto/android/server/appwindowthumbnail.proto
+++ b/core/proto/android/server/appwindowthumbnail.proto
@@ -17,6 +17,7 @@
syntax = "proto2";
import "frameworks/base/core/proto/android/server/surfaceanimator.proto";
+import "frameworks/base/libs/incident/proto/android/privacy.proto";
package com.android.server.wm.proto;
option java_multiple_files = true;
@@ -25,6 +26,8 @@
* Represents a {@link com.android.server.wm.AppWindowThumbnail} object.
*/
message AppWindowThumbnailProto {
+ option (.android.msg_privacy).dest = DEST_AUTOMATIC;
+
optional int32 width = 1;
optional int32 height = 2;
optional SurfaceAnimatorProto surface_animator = 3;
diff --git a/core/proto/android/server/fingerprint.proto b/core/proto/android/server/fingerprint.proto
index ec4ffe0..2a7fbc3 100644
--- a/core/proto/android/server/fingerprint.proto
+++ b/core/proto/android/server/fingerprint.proto
@@ -17,15 +17,21 @@
syntax = "proto2";
package com.android.server.fingerprint;
+import "frameworks/base/libs/incident/proto/android/privacy.proto";
+
option java_multiple_files = true;
option java_outer_classname = "FingerprintServiceProto";
message FingerprintServiceDumpProto {
+ option (.android.msg_privacy).dest = DEST_AUTOMATIC;
+
// Each log may include multiple tuples of (user_id, num_fingerprints).
repeated FingerprintUserStatsProto users = 1;
}
message FingerprintUserStatsProto {
+ option (.android.msg_privacy).dest = DEST_AUTOMATIC;
+
// Should be 0, 10, 11, 12, etc. where 0 is the owner.
optional int32 user_id = 1;
@@ -42,6 +48,8 @@
// A com.android.server.fingerprint.FingerpintService.PerformanceStats object.
message PerformanceStatsProto {
+ option (.android.msg_privacy).dest = DEST_AUTOMATIC;
+
// Number of accepted fingerprints.
optional int32 accept = 1;
diff --git a/core/proto/android/server/powermanagerservice.proto b/core/proto/android/server/powermanagerservice.proto
index c1bd692..babbef0 100644
--- a/core/proto/android/server/powermanagerservice.proto
+++ b/core/proto/android/server/powermanagerservice.proto
@@ -19,7 +19,7 @@
option java_multiple_files = true;
-import "frameworks/base/core/proto/android/app/activitymanager.proto";
+import "frameworks/base/core/proto/android/app/enums.proto";
import "frameworks/base/core/proto/android/content/intent.proto";
import "frameworks/base/core/proto/android/os/batterymanager.proto";
import "frameworks/base/core/proto/android/os/looper.proto";
@@ -28,13 +28,20 @@
import "frameworks/base/core/proto/android/providers/settings.proto";
import "frameworks/base/core/proto/android/server/wirelesschargerdetector.proto";
import "frameworks/base/core/proto/android/view/display.proto";
+import "frameworks/base/libs/incident/proto/android/privacy.proto";
message PowerManagerServiceDumpProto {
+ option (.android.msg_privacy).dest = DEST_AUTOMATIC;
+
// A com.android.server.power.PowerManagerService.Constants object.
message ConstantsProto {
+ option (.android.msg_privacy).dest = DEST_AUTOMATIC;
+
optional bool is_no_cached_wake_locks = 1;
}
message ActiveWakeLocksProto {
+ option (.android.msg_privacy).dest = DEST_AUTOMATIC;
+
optional bool is_cpu = 1;
optional bool is_screen_bright = 2;
optional bool is_screen_dim = 3;
@@ -46,18 +53,21 @@
optional bool is_draw = 8;
}
message UserActivityProto {
+ option (.android.msg_privacy).dest = DEST_AUTOMATIC;
+
optional bool is_screen_bright = 1;
optional bool is_screen_dim = 2;
optional bool is_screen_dream = 3;
}
// A com.android.server.power.PowerManagerService.UidState object.
message UidStateProto {
+ option (.android.msg_privacy).dest = DEST_AUTOMATIC;
+
optional int32 uid = 1;
optional string uid_string = 2;
optional bool is_active = 3;
optional int32 num_wake_locks = 4;
- optional bool is_process_state_unknown = 5;
- optional .android.app.ProcessState process_state = 6;
+ optional .android.app.ProcessStateEnum process_state = 5;
}
optional ConstantsProto constants = 1;
@@ -167,13 +177,19 @@
// A com.android.server.power.PowerManagerService.SuspendBlockerImpl object.
message SuspendBlockerProto {
+ option (.android.msg_privacy).dest = DEST_AUTOMATIC;
+
optional string name = 1;
optional int32 reference_count = 2;
}
// A com.android.server.power.PowerManagerService.WakeLock object.
message WakeLockProto {
+ option (.android.msg_privacy).dest = DEST_AUTOMATIC;
+
message WakeLockFlagsProto {
+ option (.android.msg_privacy).dest = DEST_AUTOMATIC;
+
// Turn the screen on when the wake lock is acquired.
optional bool is_acquire_causes_wakeup = 1;
// When this wake lock is released, poke the user activity timer
@@ -182,7 +198,7 @@
}
optional .android.os.PowerManagerProto.WakeLockLevel lock_level = 1;
- optional string tag = 2;
+ optional string tag = 2 [ (.android.privacy).dest = DEST_EXPLICIT ];
optional WakeLockFlagsProto flags = 3;
optional bool is_disabled = 4;
// Acquire time in ms
@@ -196,12 +212,18 @@
}
message PowerServiceSettingsAndConfigurationDumpProto {
+ option (.android.msg_privacy).dest = DEST_AUTOMATIC;
+
message StayOnWhilePluggedInProto {
+ option (.android.msg_privacy).dest = DEST_AUTOMATIC;
+
optional bool is_stay_on_while_plugged_in_ac = 1;
optional bool is_stay_on_while_plugged_in_usb = 2;
optional bool is_stay_on_while_plugged_in_wireless = 3;
}
message ScreenBrightnessSettingLimitsProto {
+ option (.android.msg_privacy).dest = DEST_AUTOMATIC;
+
optional int32 setting_minimum = 1;
optional int32 setting_maximum = 2;
optional int32 setting_default = 3;
diff --git a/core/proto/android/server/surfaceanimator.proto b/core/proto/android/server/surfaceanimator.proto
index 60713d7..7f7839e 100644
--- a/core/proto/android/server/surfaceanimator.proto
+++ b/core/proto/android/server/surfaceanimator.proto
@@ -17,6 +17,7 @@
syntax = "proto2";
import "frameworks/base/core/proto/android/view/surfacecontrol.proto";
+import "frameworks/base/libs/incident/proto/android/privacy.proto";
package com.android.server.wm.proto;
option java_multiple_files = true;
@@ -25,6 +26,8 @@
* Represents a {@link com.android.server.wm.SurfaceAnimator} object.
*/
message SurfaceAnimatorProto {
+ option (.android.msg_privacy).dest = DEST_AUTOMATIC;
+
optional string animation_adapter = 1;
optional .android.view.SurfaceControlProto leash = 2;
optional bool animation_start_delayed = 3;
diff --git a/core/proto/android/server/windowmanagerservice.proto b/core/proto/android/server/windowmanagerservice.proto
index 71f33c7..c11058a 100644
--- a/core/proto/android/server/windowmanagerservice.proto
+++ b/core/proto/android/server/windowmanagerservice.proto
@@ -26,12 +26,15 @@
import "frameworks/base/core/proto/android/view/displayinfo.proto";
import "frameworks/base/core/proto/android/view/surface.proto";
import "frameworks/base/core/proto/android/view/windowlayoutparams.proto";
+import "frameworks/base/libs/incident/proto/android/privacy.proto";
package com.android.server.wm.proto;
option java_multiple_files = true;
message WindowManagerServiceProto {
+ option (.android.msg_privacy).dest = DEST_AUTOMATIC;
+
optional WindowManagerPolicyProto policy = 1;
/* window hierarchy root */
optional RootWindowContainerProto root_window_container = 2;
@@ -46,6 +49,8 @@
/* represents DisplayContent */
message RootWindowContainerProto {
+ option (.android.msg_privacy).dest = DEST_AUTOMATIC;
+
optional WindowContainerProto window_container = 1;
repeated DisplayProto displays = 2;
/* window references in top down z order */
@@ -53,16 +58,22 @@
}
message BarControllerProto {
+ option (.android.msg_privacy).dest = DEST_AUTOMATIC;
+
optional .android.app.StatusBarManagerProto.WindowState state = 1;
optional .android.app.StatusBarManagerProto.TransientWindowState transient_state = 2;
}
message WindowOrientationListenerProto {
+ option (.android.msg_privacy).dest = DEST_AUTOMATIC;
+
optional bool enabled = 1;
optional .android.view.SurfaceProto.Rotation rotation = 2;
}
message KeyguardServiceDelegateProto {
+ option (.android.msg_privacy).dest = DEST_AUTOMATIC;
+
optional bool showing = 1;
optional bool occluded = 2;
optional bool secure = 3;
@@ -84,6 +95,8 @@
/* represents PhoneWindowManager */
message WindowManagerPolicyProto {
+ option (.android.msg_privacy).dest = DEST_AUTOMATIC;
+
optional int32 last_system_ui_flags = 1;
enum UserRotationMode {
USER_ROTATION_FREE = 0;
@@ -112,6 +125,8 @@
/* represents AppTransition */
message AppTransitionProto {
+ option (.android.msg_privacy).dest = DEST_AUTOMATIC;
+
enum AppState {
APP_STATE_IDLE = 0;
APP_STATE_READY = 1;
@@ -147,6 +162,8 @@
/* represents DisplayContent */
message DisplayProto {
+ option (.android.msg_privacy).dest = DEST_AUTOMATIC;
+
optional WindowContainerProto window_container = 1;
optional int32 id = 2;
repeated StackProto stacks = 3;
@@ -165,22 +182,30 @@
/* represents DisplayFrames */
message DisplayFramesProto {
+ option (.android.msg_privacy).dest = DEST_AUTOMATIC;
+
optional .android.graphics.RectProto stable_bounds = 1;
}
/* represents DockedStackDividerController */
message DockedStackDividerControllerProto {
+ option (.android.msg_privacy).dest = DEST_AUTOMATIC;
+
optional bool minimized_dock = 1;
}
/* represents PinnedStackController */
message PinnedStackControllerProto {
+ option (.android.msg_privacy).dest = DEST_AUTOMATIC;
+
optional .android.graphics.RectProto default_bounds = 1;
optional .android.graphics.RectProto movement_bounds = 2;
}
/* represents TaskStack */
message StackProto {
+ option (.android.msg_privacy).dest = DEST_AUTOMATIC;
+
optional WindowContainerProto window_container = 1;
optional int32 id = 2;
repeated TaskProto tasks = 3;
@@ -197,6 +222,8 @@
/* represents Task */
message TaskProto {
+ option (.android.msg_privacy).dest = DEST_AUTOMATIC;
+
optional WindowContainerProto window_container = 1;
optional int32 id = 2;
repeated AppWindowTokenProto app_window_tokens = 3;
@@ -208,8 +235,10 @@
/* represents AppWindowToken */
message AppWindowTokenProto {
+ option (.android.msg_privacy).dest = DEST_AUTOMATIC;
+
/* obtained from ActivityRecord */
- optional string name = 1;
+ optional string name = 1 [ (.android.privacy).dest = DEST_EXPLICIT ];
optional WindowTokenProto window_token = 2;
optional bool last_surface_showing = 3;
optional bool is_waiting_for_transition_start = 4;
@@ -236,6 +265,8 @@
/* represents WindowToken */
message WindowTokenProto {
+ option (.android.msg_privacy).dest = DEST_AUTOMATIC;
+
optional WindowContainerProto window_container = 1;
optional int32 hash_code = 2;
repeated WindowStateProto windows = 3;
@@ -246,6 +277,8 @@
/* represents WindowState */
message WindowStateProto {
+ option (.android.msg_privacy).dest = DEST_AUTOMATIC;
+
optional WindowContainerProto window_container = 1;
optional IdentifierProto identifier = 2;
optional int32 display_id = 3;
@@ -287,13 +320,17 @@
}
message IdentifierProto {
+ option (.android.msg_privacy).dest = DEST_AUTOMATIC;
+
optional int32 hash_code = 1;
optional int32 user_id = 2;
- optional string title = 3;
+ optional string title = 3 [ (.android.privacy).dest = DEST_EXPLICIT ];
}
/* represents WindowStateAnimator */
message WindowStateAnimatorProto {
+ option (.android.msg_privacy).dest = DEST_AUTOMATIC;
+
optional .android.graphics.RectProto last_clip_rect = 1;
optional WindowSurfaceControllerProto surface = 2;
enum DrawState {
@@ -309,18 +346,24 @@
/* represents WindowSurfaceController */
message WindowSurfaceControllerProto {
+ option (.android.msg_privacy).dest = DEST_AUTOMATIC;
+
optional bool shown = 1;
optional int32 layer = 2;
}
/* represents ScreenRotationAnimation */
message ScreenRotationAnimationProto {
+ option (.android.msg_privacy).dest = DEST_AUTOMATIC;
+
optional bool started = 1;
optional bool animation_running = 2;
}
/* represents WindowContainer */
message WindowContainerProto {
+ option (.android.msg_privacy).dest = DEST_AUTOMATIC;
+
optional ConfigurationContainerProto configuration_container = 1;
optional int32 orientation = 2;
optional bool visible = 3;
@@ -329,6 +372,8 @@
/* represents ConfigurationContainer */
message ConfigurationContainerProto {
+ option (.android.msg_privacy).dest = DEST_AUTOMATIC;
+
optional .android.content.ConfigurationProto override_configuration = 1;
optional .android.content.ConfigurationProto full_configuration = 2;
optional .android.content.ConfigurationProto merged_override_configuration = 3;
diff --git a/core/proto/android/service/diskstats.proto b/core/proto/android/service/diskstats.proto
index 3c7a0e3..3d7ee91 100644
--- a/core/proto/android/service/diskstats.proto
+++ b/core/proto/android/service/diskstats.proto
@@ -17,10 +17,14 @@
syntax = "proto2";
package android.service.diskstats;
+import "frameworks/base/libs/incident/proto/android/privacy.proto";
+
option java_multiple_files = true;
option java_outer_classname = "DiskStatsServiceProto";
message DiskStatsServiceDumpProto {
+ option (android.msg_privacy).dest = DEST_AUTOMATIC;
+
enum EncryptionType {
// Unknown encryption type
ENCRYPTION_UNKNOWN = 0;
@@ -34,7 +38,7 @@
// Whether the latency test resulted in an error
optional bool has_test_error = 1;
// If the test errored, error message is contained here
- optional string error_message = 2;
+ optional string error_message = 2 [ (android.privacy).dest = DEST_EXPLICIT ];
// 512B write latency in milliseconds, if the test was successful
optional int32 write_512b_latency_millis = 3;
// Free Space in the major partitions
@@ -48,6 +52,8 @@
}
message DiskStatsCachedValuesProto {
+ option (android.msg_privacy).dest = DEST_AUTOMATIC;
+
// Total app code size, in kilobytes
optional int64 agg_apps_size = 1;
// Total app cache size, in kilobytes
@@ -71,6 +77,8 @@
}
message DiskStatsAppSizesProto {
+ option (android.msg_privacy).dest = DEST_AUTOMATIC;
+
// Name of the package
optional string package_name = 1;
// App's code size in kilobytes
@@ -82,6 +90,8 @@
}
message DiskStatsFreeSpaceProto {
+ option (android.msg_privacy).dest = DEST_AUTOMATIC;
+
enum Folder {
// Data folder
FOLDER_DATA = 0;
diff --git a/core/proto/android/service/netstats.proto b/core/proto/android/service/netstats.proto
index ad9191c..29fd195 100644
--- a/core/proto/android/service/netstats.proto
+++ b/core/proto/android/service/netstats.proto
@@ -17,11 +17,15 @@
syntax = "proto2";
package android.service;
+import "frameworks/base/libs/incident/proto/android/privacy.proto";
+
option java_multiple_files = true;
option java_outer_classname = "NetworkStatsServiceProto";
// Represents dumpsys from NetworkStatsService (netstats).
message NetworkStatsServiceDumpProto {
+ option (android.msg_privacy).dest = DEST_AUTOMATIC;
+
repeated NetworkInterfaceProto active_interfaces = 1;
repeated NetworkInterfaceProto active_uid_interfaces = 2;
@@ -41,6 +45,8 @@
// Corresponds to NetworkStatsService.mActiveIfaces/mActiveUidIfaces.
message NetworkInterfaceProto {
+ option (android.msg_privacy).dest = DEST_AUTOMATIC;
+
optional string interface = 1;
optional NetworkIdentitySetProto identities = 2;
@@ -48,17 +54,21 @@
// Corresponds to NetworkIdentitySet.
message NetworkIdentitySetProto {
+ option (android.msg_privacy).dest = DEST_AUTOMATIC;
+
repeated NetworkIdentityProto identities = 1;
}
// Corresponds to NetworkIdentity.
message NetworkIdentityProto {
+ option (android.msg_privacy).dest = DEST_AUTOMATIC;
+
// Constats from ConnectivityManager.TYPE_*.
optional int32 type = 1;
- optional string subscriber_id = 2;
+ optional string subscriber_id = 2 [ (android.privacy).dest = DEST_EXPLICIT ];
- optional string network_id = 3;
+ optional string network_id = 3 [ (android.privacy).dest = DEST_EXPLICIT ];
optional bool roaming = 4;
@@ -69,6 +79,8 @@
// Corresponds to NetworkStatsRecorder.
message NetworkStatsRecorderProto {
+ option (android.msg_privacy).dest = DEST_AUTOMATIC;
+
optional int64 pending_total_bytes = 1;
optional NetworkStatsCollectionProto complete_history = 2;
@@ -76,11 +88,15 @@
// Corresponds to NetworkStatsCollection.
message NetworkStatsCollectionProto {
+ option (android.msg_privacy).dest = DEST_AUTOMATIC;
+
repeated NetworkStatsCollectionStatsProto stats = 1;
}
// Corresponds to NetworkStatsCollection.mStats.
message NetworkStatsCollectionStatsProto {
+ option (android.msg_privacy).dest = DEST_AUTOMATIC;
+
optional NetworkStatsCollectionKeyProto key = 1;
optional NetworkStatsHistoryProto history = 2;
@@ -88,6 +104,8 @@
// Corresponds to NetworkStatsCollection.Key.
message NetworkStatsCollectionKeyProto {
+ option (android.msg_privacy).dest = DEST_AUTOMATIC;
+
optional NetworkIdentitySetProto identity = 1;
optional int32 uid = 2;
@@ -99,6 +117,8 @@
// Corresponds to NetworkStatsHistory.
message NetworkStatsHistoryProto {
+ option (android.msg_privacy).dest = DEST_AUTOMATIC;
+
// Duration for this bucket in milliseconds.
optional int64 bucket_duration_ms = 1;
@@ -107,6 +127,8 @@
// Corresponds to each bucket in NetworkStatsHistory.
message NetworkStatsHistoryBucketProto {
+ option (android.msg_privacy).dest = DEST_AUTOMATIC;
+
// Bucket start time in milliseconds since epoch.
optional int64 bucket_start_ms = 1;
diff --git a/core/proto/android/service/package.proto b/core/proto/android/service/package.proto
index aa1a575..ef777de 100644
--- a/core/proto/android/service/package.proto
+++ b/core/proto/android/service/package.proto
@@ -18,18 +18,25 @@
package android.service.pm;
import "frameworks/base/core/proto/android/content/featureinfo.proto";
+import "frameworks/base/libs/incident/proto/android/privacy.proto";
option java_multiple_files = true;
option java_outer_classname = "PackageServiceProto";
message PackageServiceDumpProto {
+ option (android.msg_privacy).dest = DEST_AUTOMATIC;
+
message PackageShortProto {
+ option (android.msg_privacy).dest = DEST_AUTOMATIC;
+
// Name of package. e.g. "com.android.providers.telephony".
optional string name = 1;
// UID for this package as assigned by Android OS.
optional int32 uid = 2;
}
message SharedLibraryProto {
+ option (android.msg_privacy).dest = DEST_AUTOMATIC;
+
optional string name = 1;
// True if library path is not null (jar), false otherwise (apk)
optional bool is_jar = 2;
@@ -39,8 +46,10 @@
optional string apk = 4;
}
message SharedUserProto {
+ option (android.msg_privacy).dest = DEST_AUTOMATIC;
+
optional int32 user_id = 1;
- optional string name = 2;
+ optional string name = 2 [ (android.privacy).dest = DEST_EXPLICIT ];
}
// Installed packages.
@@ -51,15 +60,22 @@
repeated PackageProto packages = 5;
repeated SharedUserProto shared_users = 6;
// Messages from the settings problem file
- repeated string messages = 7;
+ repeated string messages = 7 [ (android.privacy).dest = DEST_EXPLICIT ];
}
message PackageProto {
+ option (android.msg_privacy).dest = DEST_AUTOMATIC;
+
message SplitProto {
+ option (android.msg_privacy).dest = DEST_AUTOMATIC;
+
+ // The split name of package, e.g. base
optional string name = 1;
optional int32 revision_code = 2;
}
message UserInfoProto {
+ option (android.msg_privacy).dest = DEST_AUTOMATIC;
+
enum InstallType {
NOT_INSTALLED_FOR_USER = 0;
FULL_APP_INSTALL = 1;
diff --git a/core/proto/android/service/procstats.proto b/core/proto/android/service/procstats.proto
index b2e0373..4c11f1e 100644
--- a/core/proto/android/service/procstats.proto
+++ b/core/proto/android/service/procstats.proto
@@ -19,6 +19,7 @@
option java_outer_classname = "ProcessStatsServiceProto";
import "frameworks/base/core/proto/android/util/common.proto";
+import "frameworks/base/libs/incident/proto/android/privacy.proto";
package android.service.procstats;
@@ -28,6 +29,7 @@
* Next Tag: 4
*/
message ProcessStatsServiceDumpProto {
+ option (android.msg_privacy).dest = DEST_AUTOMATIC;
optional ProcessStatsSectionProto procstats_now = 1;
@@ -43,6 +45,7 @@
* Next Tag: 9
*/
message ProcessStatsSectionProto {
+ option (android.msg_privacy).dest = DEST_AUTOMATIC;
// Elapsed realtime at start of report.
optional int64 start_realtime_ms = 1;
@@ -78,6 +81,7 @@
// Next Tag: 6
message ProcessStatsProto {
+ option (android.msg_privacy).dest = DEST_AUTOMATIC;
// Name of process.
optional string process = 1;
@@ -87,6 +91,8 @@
// Information about how often kills occurred
message Kill {
+ option (android.msg_privacy).dest = DEST_AUTOMATIC;
+
// Count of excessive CPU kills
optional int32 cpu = 1;
@@ -99,6 +105,8 @@
optional Kill kill = 3;
message State {
+ option (android.msg_privacy).dest = DEST_AUTOMATIC;
+
enum ScreenState {
SCREEN_UNKNOWN = 0;
OFF = 1;
@@ -115,6 +123,8 @@
}
optional MemoryState memory_state = 2;
+ // this enum list is from frameworks/base/core/java/com/android/internal/app/procstats/ProcessStats.java
+ // and not frameworks/base/core/java/android/app/ActivityManager.java
enum ProcessState {
PROCESS_UNKNOWN = 0;
// Persistent system process.
@@ -127,14 +137,14 @@
IMPORTANT_BACKGROUND = 4;
// Performing backup operation.
BACKUP = 5;
- // Heavy-weight process (currently not used).
- HEAVY_WEIGHT = 6;
// Background process running a service.
- SERVICE = 7;
+ SERVICE = 6;
// Process not running, but would be if there was enough RAM.
- SERVICE_RESTARTING = 8;
+ SERVICE_RESTARTING = 7;
// Process running a receiver.
- RECEIVER = 9;
+ RECEIVER = 8;
+ // Heavy-weight process (currently not used).
+ HEAVY_WEIGHT = 9;
// Process hosting home/launcher app when not on top.
HOME = 10;
// Process hosting the last app the user was in.
diff --git a/core/proto/android/util/common.proto b/core/proto/android/util/common.proto
index 308ef70..f8f7885 100644
--- a/core/proto/android/util/common.proto
+++ b/core/proto/android/util/common.proto
@@ -17,12 +17,15 @@
syntax = "proto2";
package android.util;
+import "frameworks/base/libs/incident/proto/android/privacy.proto";
+
option java_multiple_files = true;
/**
* Very basic data structure used by aggregated stats.
*/
message AggStats {
+ option (android.msg_privacy).dest = DEST_AUTOMATIC;
optional int64 min = 1;
@@ -35,6 +38,7 @@
* Very basic data structure to represent Duration.
*/
message Duration {
+ option (android.msg_privacy).dest = DEST_AUTOMATIC;
optional int64 start_ms = 1;
diff --git a/core/proto/android/util/log.proto b/core/proto/android/util/log.proto
index fd4fa9e..416c055 100644
--- a/core/proto/android/util/log.proto
+++ b/core/proto/android/util/log.proto
@@ -17,11 +17,15 @@
syntax = "proto2";
package android.util;
+import "frameworks/base/libs/incident/proto/android/privacy.proto";
+
option java_multiple_files = true;
// Represents a Text Log in logd
// Next Tag: 9
message TextLogEntry {
+ option (android.msg_privacy).dest = DEST_EXPLICIT;
+
optional uint64 sec = 1;
optional uint64 nanosec = 2;
@@ -47,6 +51,8 @@
// Represents a Binary Log in logd, need to look event-log-tags for more info.
// Next Tag: 8
message BinaryLogEntry {
+ option (android.msg_privacy).dest = DEST_EXPLICIT;
+
optional uint64 sec = 1;
optional uint64 nanosec = 2;
optional int32 uid = 3;
@@ -81,6 +87,8 @@
}
message LogProto {
+ option (android.msg_privacy).dest = DEST_EXPLICIT;
+
repeated TextLogEntry text_logs = 1;
repeated BinaryLogEntry binary_logs = 2;
diff --git a/core/proto/android/view/displayinfo.proto b/core/proto/android/view/displayinfo.proto
index 9ca4046..3ac8f3b 100644
--- a/core/proto/android/view/displayinfo.proto
+++ b/core/proto/android/view/displayinfo.proto
@@ -17,10 +17,14 @@
syntax = "proto2";
package android.view;
+import "frameworks/base/libs/incident/proto/android/privacy.proto";
+
option java_multiple_files = true;
/* represents DisplayInfo */
message DisplayInfoProto {
+ option (.android.msg_privacy).dest = DEST_AUTOMATIC;
+
optional int32 logical_width = 1;
optional int32 logical_height = 2;
optional int32 app_width = 3;
diff --git a/core/proto/android/view/windowlayoutparams.proto b/core/proto/android/view/windowlayoutparams.proto
index f079e1e..0362ab1 100644
--- a/core/proto/android/view/windowlayoutparams.proto
+++ b/core/proto/android/view/windowlayoutparams.proto
@@ -18,12 +18,15 @@
import "frameworks/base/core/proto/android/graphics/pixelformat.proto";
import "frameworks/base/core/proto/android/view/display.proto";
+import "frameworks/base/libs/incident/proto/android/privacy.proto";
package android.view;
option java_multiple_files = true;
/* represents WindowManager.LayoutParams */
message WindowLayoutParamsProto {
+ option (.android.msg_privacy).dest = DEST_AUTOMATIC;
+
optional int32 type = 1;
optional int32 x = 2;
optional int32 y = 3;
diff --git a/core/res/res/anim/cross_profile_apps_thumbnail_enter.xml b/core/res/res/anim/cross_profile_apps_thumbnail_enter.xml
index 3254ebb..6f3dc8c 100644
--- a/core/res/res/anim/cross_profile_apps_thumbnail_enter.xml
+++ b/core/res/res/anim/cross_profile_apps_thumbnail_enter.xml
@@ -20,19 +20,54 @@
<set xmlns:android="http://schemas.android.com/apk/res/android"
android:shareInterpolator="false" android:zAdjustment="top">
- <alpha android:fromAlpha="0" android:toAlpha="1.0"
- android:startOffset="300"
- android:fillEnabled="true" android:fillBefore="true" android:fillAfter="true"
- android:interpolator="@interpolator/decelerate_quart"
- android:duration="167"/>
+ <alpha
+ android:fromAlpha="1"
+ android:toAlpha="1.0"
+ android:fillEnabled="true"
+ android:fillBefore="true"
+ android:fillAfter="true"
+ android:interpolator="@interpolator/linear"
+ android:startOffset="67"
+ android:duration="217"/>
- <translate android:fromYDelta="110%" android:toYDelta="0"
- android:startOffset="300"
- android:fillEnabled="true" android:fillBefore="true" android:fillAfter="true"
- android:interpolator="@interpolator/decelerate_quint"
- android:duration="417"/>
+ <translate
+ android:fromXDelta="-105%"
+ android:toXDelta="0"
+ android:fillEnabled="true"
+ android:fillBefore="true"
+ android:fillAfter="true"
+ android:interpolator="@interpolator/aggressive_ease"
+ android:startOffset="50"
+ android:duration="383"/>
- <!-- To keep the thumbnail around longer -->
+ <scale
+ android:fromXScale="1.0526"
+ android:toXScale="1"
+ android:fromYScale="1.0526"
+ android:toYScale="1"
+ android:pivotX="50%"
+ android:pivotY="50%"
+ android:fillEnabled="true"
+ android:fillBefore="true"
+ android:fillAfter="true"
+ android:interpolator="@interpolator/fast_out_slow_in"
+ android:duration="283"/>
+
+ <scale
+ android:fromXScale="0.95"
+ android:toXScale="1"
+ android:fromYScale="0.95"
+ android:toYScale="1"
+ android:pivotX="50%"
+ android:pivotY="50%"
+ android:fillEnabled="true"
+ android:fillBefore="true"
+ android:fillAfter="true"
+ android:interpolator="@interpolator/fast_out_slow_in"
+ android:startOffset="283"
+ android:duration="317"/>
+
+ <!-- To keep the thumbnail around longer and fade out the thumbnail -->
<alpha android:fromAlpha="1.0" android:toAlpha="0"
android:fillEnabled="true" android:fillBefore="true" android:fillAfter="true"
android:interpolator="@interpolator/decelerate_quint"
diff --git a/core/res/res/anim/task_open_enter.xml b/core/res/res/anim/task_open_enter.xml
index 2ee7cd8..0e66eda 100644
--- a/core/res/res/anim/task_open_enter.xml
+++ b/core/res/res/anim/task_open_enter.xml
@@ -14,7 +14,9 @@
** See the License for the specific language governing permissions and
** limitations under the License.
*/
---><!-- This should in sync with task_open_enter_cross_profile_apps.xml -->
+-->
+<!-- This should in sync with task_open_enter_cross_profile_apps.xml -->
+<!-- This should in sync with cross_profile_apps_thumbnail_enter.xml -->
<set xmlns:android="http://schemas.android.com/apk/res/android"
android:shareInterpolator="false"
android:zAdjustment="top">
diff --git a/core/res/res/values/colors_material.xml b/core/res/res/values/colors_material.xml
index f8a77f8..ce4ac61 100644
--- a/core/res/res/values/colors_material.xml
+++ b/core/res/res/values/colors_material.xml
@@ -44,7 +44,8 @@
<color name="button_material_dark">#ff5a595b</color>
<color name="button_material_light">#ffd6d7d7</color>
- <color name="error_color_material">#F4511E</color>
+ <color name="error_color_material_dark">#ff7043</color><!-- deep orange 400 -->
+ <color name="error_color_material_light">#ff5722</color><!-- deep orange 500 -->
<color name="switch_thumb_normal_material_dark">#ffbdbdbd</color>
<color name="switch_thumb_normal_material_light">#fff1f1f1</color>
diff --git a/core/res/res/values/strings.xml b/core/res/res/values/strings.xml
index 012212f3..69d96fc 100644
--- a/core/res/res/values/strings.xml
+++ b/core/res/res/values/strings.xml
@@ -2731,6 +2731,15 @@
<!-- Label for item in the text selection menu to trigger adding a contact [CHAR LIMIT=20] -->
<string name="add_contact">Add</string>
+ <!-- Label for item in the text selection menu to view the calendar for the selected time/date [CHAR LIMIT=20] -->
+ <string name="view_calendar">View</string>
+
+ <!-- Label for item in the text selection menu to create a calendar event at the selected time/date [CHAR LIMIT=20] -->
+ <string name="add_calendar_event">Schedule</string>
+
+ <!-- Label for item in the text selection menu to track a selected flight number [CHAR LIMIT=20] -->
+ <string name="view_flight">Track</string>
+
<!-- If the device is getting low on internal storage, a notification is shown to the user. This is the title of that notification. -->
<string name="low_internal_storage_view_title">Storage space running out</string>
<!-- If the device is getting low on internal storage, a notification is shown to the user. This is the message of that notification. -->
diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml
index f94168d..710bbfb 100644
--- a/core/res/res/values/symbols.xml
+++ b/core/res/res/values/symbols.xml
@@ -533,6 +533,9 @@
<java-symbol type="string" name="browse" />
<java-symbol type="string" name="sms" />
<java-symbol type="string" name="add_contact" />
+ <java-symbol type="string" name="view_calendar" />
+ <java-symbol type="string" name="add_calendar_event" />
+ <java-symbol type="string" name="view_flight" />
<java-symbol type="string" name="textSelectionCABTitle" />
<java-symbol type="string" name="BaMmi" />
<java-symbol type="string" name="CLIRDefaultOffNextCallOff" />
diff --git a/core/res/res/values/themes_material.xml b/core/res/res/values/themes_material.xml
index 9e6b1ab..15d8fb7 100644
--- a/core/res/res/values/themes_material.xml
+++ b/core/res/res/values/themes_material.xml
@@ -51,7 +51,7 @@
<item name="primaryContentAlpha">@dimen/primary_content_alpha_material_dark</item>
<item name="secondaryContentAlpha">@dimen/secondary_content_alpha_material_dark</item>
<item name="backgroundDimAmount">0.6</item>
- <item name="colorError">@color/error_color_material</item>
+ <item name="colorError">@color/error_color_material_dark</item>
<!-- Text styles -->
<item name="textAppearance">@style/TextAppearance.Material</item>
@@ -420,6 +420,7 @@
<item name="primaryContentAlpha">@dimen/primary_content_alpha_material_light</item>
<item name="secondaryContentAlpha">@dimen/secondary_content_alpha_material_light</item>
<item name="backgroundDimAmount">0.6</item>
+ <item name="colorError">@color/error_color_material_light</item>
<!-- Text styles -->
<item name="textAppearance">@style/TextAppearance.Material</item>
@@ -811,6 +812,7 @@
<item name="colorBackground">@color/background_material_light</item>
<item name="colorBackgroundFloating">@color/background_floating_material_light</item>
<item name="colorBackgroundCacheHint">@color/background_cache_hint_selector_material_light</item>
+ <item name="colorError">@color/error_color_material_light</item>
<item name="textColorPrimary">@color/text_color_primary</item>
<item name="textColorPrimaryInverse">@color/primary_text_material_dark</item>
@@ -844,6 +846,7 @@
<item name="colorBackground">@color/background_material_dark</item>
<item name="colorBackgroundFloating">@color/background_floating_material_dark</item>
<item name="colorBackgroundCacheHint">@color/background_cache_hint_selector_material_dark</item>
+ <item name="colorError">@color/error_color_material_dark</item>
<item name="textColorPrimary">@color/text_color_primary</item>
<item name="textColorPrimaryInverse">@color/primary_text_material_light</item>
diff --git a/core/tests/BroadcastRadioTests/src/android/hardware/radio/tests/functional/RadioTunerTest.java b/core/tests/BroadcastRadioTests/src/android/hardware/radio/tests/functional/RadioTunerTest.java
index 896fd15..370659e 100644
--- a/core/tests/BroadcastRadioTests/src/android/hardware/radio/tests/functional/RadioTunerTest.java
+++ b/core/tests/BroadcastRadioTests/src/android/hardware/radio/tests/functional/RadioTunerTest.java
@@ -122,6 +122,7 @@
private void resetCallback() {
verify(mCallback, atLeast(0)).onMetadataChanged(any());
+ verify(mCallback, atLeast(0)).onProgramInfoChanged(any());
verifyNoMoreInteractions(mCallback);
Mockito.reset(mCallback);
}
diff --git a/core/tests/coretests/AndroidManifest.xml b/core/tests/coretests/AndroidManifest.xml
index 3e38010..53c22f6 100644
--- a/core/tests/coretests/AndroidManifest.xml
+++ b/core/tests/coretests/AndroidManifest.xml
@@ -1045,6 +1045,13 @@
</intent-filter>
</activity>
+ <activity android:name="android.view.menu.ContextMenuActivity" android:label="ContextMenu" android:theme="@android:style/Theme.Material">
+ <intent-filter>
+ <action android:name="android.intent.action.MAIN" />
+ <category android:name="android.intent.category.FRAMEWORK_INSTRUMENTATION_TEST" />
+ </intent-filter>
+ </activity>
+
<activity android:name="android.view.menu.MenuWith1Item" android:label="MenuWith1Item">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
diff --git a/core/tests/coretests/res/layout/context_menu.xml b/core/tests/coretests/res/layout/context_menu.xml
new file mode 100644
index 0000000..3b9e2bd
--- /dev/null
+++ b/core/tests/coretests/res/layout/context_menu.xml
@@ -0,0 +1,54 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/*
+**
+** Copyright 2018, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+** http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+-->
+
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ android:orientation="vertical"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent">
+
+ <LinearLayout
+ android:id="@+id/context_menu_target_ltr"
+ android:orientation="horizontal"
+ android:layoutDirection="ltr"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:layout_marginStart="50px"
+ android:layout_marginEnd="50px">
+ <TextView
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:text="LTR"/>
+ </LinearLayout>
+
+ <LinearLayout
+ android:id="@+id/context_menu_target_rtl"
+ android:orientation="horizontal"
+ android:layoutDirection="rtl"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:layout_marginStart="50px"
+ android:layout_marginEnd="50px">
+ <TextView
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:text="RTL"/>
+ </LinearLayout>
+
+</LinearLayout>
diff --git a/core/tests/coretests/src/android/os/WorkSourceTest.java b/core/tests/coretests/src/android/os/WorkSourceTest.java
index a427a2f..952a64d 100644
--- a/core/tests/coretests/src/android/os/WorkSourceTest.java
+++ b/core/tests/coretests/src/android/os/WorkSourceTest.java
@@ -349,6 +349,15 @@
assertEquals(100, wc.getAttributionUid());
}
+ public void testGetAttributionTag() {
+ WorkSource ws1 = new WorkSource();
+ WorkChain wc = ws1.createWorkChain();
+ wc.addNode(100, "tag");
+ assertEquals("tag", wc.getAttributionTag());
+ wc.addNode(200, "tag2");
+ assertEquals("tag", wc.getAttributionTag());
+ }
+
public void testRemove_fromChainedWorkSource() {
WorkSource ws1 = new WorkSource();
ws1.createWorkChain().addNode(50, "foo");
@@ -368,4 +377,25 @@
assertEquals(1, ws1.getWorkChains().size());
assertEquals(75, ws1.getWorkChains().get(0).getAttributionUid());
}
+
+ public void testTransferWorkChains() {
+ WorkSource ws1 = new WorkSource();
+ WorkChain wc1 = ws1.createWorkChain().addNode(100, "tag");
+ WorkChain wc2 = ws1.createWorkChain().addNode(200, "tag2");
+
+ WorkSource ws2 = new WorkSource();
+ ws2.transferWorkChains(ws1);
+
+ assertEquals(0, ws1.getWorkChains().size());
+ assertEquals(2, ws2.getWorkChains().size());
+ assertSame(wc1, ws2.getWorkChains().get(0));
+ assertSame(wc2, ws2.getWorkChains().get(1));
+
+ ws1.clear();
+ ws1.createWorkChain().addNode(300, "tag3");
+ ws1.transferWorkChains(ws2);
+ assertEquals(0, ws2.getWorkChains().size());
+ assertSame(wc1, ws1.getWorkChains().get(0));
+ assertSame(wc2, ws1.getWorkChains().get(1));
+ }
}
diff --git a/core/tests/coretests/src/android/provider/SettingsBackupTest.java b/core/tests/coretests/src/android/provider/SettingsBackupTest.java
index 1520fb6..2f747ec 100644
--- a/core/tests/coretests/src/android/provider/SettingsBackupTest.java
+++ b/core/tests/coretests/src/android/provider/SettingsBackupTest.java
@@ -497,6 +497,7 @@
Settings.Secure.INPUT_METHODS_SUBTYPE_HISTORY,
Settings.Secure.INSTALL_NON_MARKET_APPS,
Settings.Secure.LAST_SETUP_SHOWN,
+ Settings.Secure.LOCATION_CHANGER,
Settings.Secure.LOCATION_MODE,
Settings.Secure.LOCK_SCREEN_ALLOW_PRIVATE_NOTIFICATIONS, // Candidate?
Settings.Secure.LOCK_SCREEN_ALLOW_REMOTE_INPUT, // Candidate?
diff --git a/core/tests/coretests/src/android/util/PollingCheck.java b/core/tests/coretests/src/android/util/PollingCheck.java
new file mode 100644
index 0000000..468b9b2
--- /dev/null
+++ b/core/tests/coretests/src/android/util/PollingCheck.java
@@ -0,0 +1,104 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.util;
+
+import org.junit.Assert;
+
+/**
+ * Utility used for testing that allows to poll for a certain condition to happen within a timeout.
+ *
+ * Code copied from com.android.compatibility.common.util.PollingCheck
+ */
+public abstract class PollingCheck {
+
+ private static final long DEFAULT_TIMEOUT = 3000;
+ private static final long TIME_SLICE = 50;
+ private final long mTimeout;
+
+ /**
+ * The condition that the PollingCheck should use to proceed successfully.
+ */
+ public interface PollingCheckCondition {
+
+ /**
+ * @return Whether the polling condition has been met.
+ */
+ boolean canProceed();
+ }
+
+ public PollingCheck(long timeout) {
+ mTimeout = timeout;
+ }
+
+ protected abstract boolean check();
+
+ /**
+ * Start running the polling check.
+ */
+ public void run() {
+ if (check()) {
+ return;
+ }
+
+ long timeout = mTimeout;
+ while (timeout > 0) {
+ try {
+ Thread.sleep(TIME_SLICE);
+ } catch (InterruptedException e) {
+ Assert.fail("unexpected InterruptedException");
+ }
+
+ if (check()) {
+ return;
+ }
+
+ timeout -= TIME_SLICE;
+ }
+
+ Assert.fail("unexpected timeout");
+ }
+
+ /**
+ * Instantiate and start polling for a given condition with a default 3000ms timeout.
+ *
+ * @param condition The condition to check for success.
+ */
+ public static void waitFor(final PollingCheckCondition condition) {
+ new PollingCheck(DEFAULT_TIMEOUT) {
+ @Override
+ protected boolean check() {
+ return condition.canProceed();
+ }
+ }.run();
+ }
+
+ /**
+ * Instantiate and start polling for a given condition.
+ *
+ * @param timeout Time out in ms
+ * @param condition The condition to check for success.
+ */
+ public static void waitFor(long timeout, final PollingCheckCondition condition) {
+ new PollingCheck(timeout) {
+ @Override
+ protected boolean check() {
+ return condition.canProceed();
+ }
+ }.run();
+ }
+}
+
diff --git a/core/tests/coretests/src/android/view/menu/ContextMenuActivity.java b/core/tests/coretests/src/android/view/menu/ContextMenuActivity.java
new file mode 100644
index 0000000..830b3d5
--- /dev/null
+++ b/core/tests/coretests/src/android/view/menu/ContextMenuActivity.java
@@ -0,0 +1,54 @@
+/*
+ * Copyright (C) 2018 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.menu;
+
+import android.app.Activity;
+import android.os.Bundle;
+import android.view.ContextMenu;
+import android.view.ContextMenu.ContextMenuInfo;
+import android.view.View;
+
+import com.android.frameworks.coretests.R;
+
+public class ContextMenuActivity extends Activity {
+
+ static final String LABEL_ITEM = "Item";
+ static final String LABEL_SUBMENU = "Submenu";
+ static final String LABEL_SUBITEM = "Subitem";
+
+ @Override
+ protected void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ setContentView(R.layout.context_menu);
+ registerForContextMenu(getTargetLtr());
+ registerForContextMenu(getTargetRtl());
+ }
+
+ @Override
+ public void onCreateContextMenu(ContextMenu menu, View v, ContextMenuInfo menuInfo) {
+ menu.add(LABEL_ITEM);
+ menu.addSubMenu(LABEL_SUBMENU).add(LABEL_SUBITEM);
+ }
+
+ View getTargetLtr() {
+ return findViewById(R.id.context_menu_target_ltr);
+ }
+
+ View getTargetRtl() {
+ return findViewById(R.id.context_menu_target_rtl);
+ }
+}
diff --git a/core/tests/coretests/src/android/view/menu/ContextMenuTest.java b/core/tests/coretests/src/android/view/menu/ContextMenuTest.java
new file mode 100644
index 0000000..59d4e55
--- /dev/null
+++ b/core/tests/coretests/src/android/view/menu/ContextMenuTest.java
@@ -0,0 +1,93 @@
+/*
+ * Copyright (C) 2018 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.menu;
+
+import android.content.Context;
+import android.graphics.Point;
+import android.support.test.filters.MediumTest;
+import android.test.ActivityInstrumentationTestCase;
+import android.util.PollingCheck;
+import android.view.Display;
+import android.view.View;
+import android.view.WindowManager;
+import android.widget.espresso.ContextMenuUtils;
+
+@MediumTest
+public class ContextMenuTest extends ActivityInstrumentationTestCase<ContextMenuActivity> {
+
+ public ContextMenuTest() {
+ super("com.android.frameworks.coretests", ContextMenuActivity.class);
+ }
+
+ public void testContextMenuPositionLtr() throws InterruptedException {
+ testMenuPosition(getActivity().getTargetLtr());
+ }
+
+ public void testContextMenuPositionRtl() throws InterruptedException {
+ testMenuPosition(getActivity().getTargetRtl());
+ }
+
+ private void testMenuPosition(View target) throws InterruptedException {
+ final int minScreenDimension = getMinScreenDimension();
+ if (minScreenDimension < 320) {
+ // Assume there is insufficient room for the context menu to be aligned properly.
+ return;
+ }
+
+ int offsetX = target.getWidth() / 2;
+ int offsetY = target.getHeight() / 2;
+
+ getInstrumentation().runOnMainSync(() -> target.performLongClick(offsetX, offsetY));
+
+ PollingCheck.waitFor(
+ () -> ContextMenuUtils.isMenuItemClickable(ContextMenuActivity.LABEL_SUBMENU));
+
+ ContextMenuUtils.assertContextMenuAlignment(target, offsetX, offsetY);
+
+ ContextMenuUtils.clickMenuItem(ContextMenuActivity.LABEL_SUBMENU);
+
+ PollingCheck.waitFor(
+ () -> ContextMenuUtils.isMenuItemClickable(ContextMenuActivity.LABEL_SUBITEM));
+
+ if (minScreenDimension < getCascadingMenuTreshold()) {
+ // A non-cascading submenu should be displayed at the same location as its parent.
+ // Not testing cascading submenu position, as it is positioned differently.
+ ContextMenuUtils.assertContextMenuAlignment(target, offsetX, offsetY);
+ }
+ }
+
+ /**
+ * Returns the minimum of the default display's width and height.
+ */
+ private int getMinScreenDimension() {
+ final WindowManager windowManager = (WindowManager) getActivity().getSystemService(
+ Context.WINDOW_SERVICE);
+ final Display display = windowManager.getDefaultDisplay();
+ final Point displaySize = new Point();
+ display.getRealSize(displaySize);
+ return Math.min(displaySize.x, displaySize.y);
+ }
+
+ /**
+ * Returns the minimum display size where cascading submenus are supported.
+ */
+ private int getCascadingMenuTreshold() {
+ // Use the same dimension resource as in MenuPopupHelper.createPopup().
+ return getActivity().getResources().getDimensionPixelSize(
+ com.android.internal.R.dimen.cascading_menus_min_smallest_width);
+ }
+}
diff --git a/core/tests/coretests/src/android/view/textclassifier/TextClassificationTest.java b/core/tests/coretests/src/android/view/textclassifier/TextClassificationTest.java
index 9ee7fac..8a81743 100644
--- a/core/tests/coretests/src/android/view/textclassifier/TextClassificationTest.java
+++ b/core/tests/coretests/src/android/view/textclassifier/TextClassificationTest.java
@@ -32,7 +32,9 @@
import org.junit.Test;
import org.junit.runner.RunWith;
+import java.util.Calendar;
import java.util.Locale;
+import java.util.TimeZone;
@SmallTest
@RunWith(AndroidJUnit4.class)
@@ -146,8 +148,12 @@
@Test
public void testParcelOptions() {
+ Calendar referenceTime = Calendar.getInstance(TimeZone.getTimeZone("UTC"), Locale.US);
+ referenceTime.setTimeInMillis(946771200000L); // 2000-01-02
+
TextClassification.Options reference = new TextClassification.Options();
reference.setDefaultLocales(new LocaleList(Locale.US, Locale.GERMANY));
+ reference.setReferenceTime(referenceTime);
// Parcel and unparcel.
final Parcel parcel = Parcel.obtain();
@@ -157,5 +163,6 @@
parcel);
assertEquals("en-US,de-DE", result.getDefaultLocales().toLanguageTags());
+ assertEquals(referenceTime, result.getReferenceTime());
}
}
diff --git a/core/tests/coretests/src/android/widget/espresso/ContextMenuUtils.java b/core/tests/coretests/src/android/widget/espresso/ContextMenuUtils.java
index c8218aa..02ee9be 100644
--- a/core/tests/coretests/src/android/widget/espresso/ContextMenuUtils.java
+++ b/core/tests/coretests/src/android/widget/espresso/ContextMenuUtils.java
@@ -17,25 +17,33 @@
package android.widget.espresso;
import static android.support.test.espresso.Espresso.onView;
+import static android.support.test.espresso.action.ViewActions.click;
import static android.support.test.espresso.assertion.ViewAssertions.matches;
import static android.support.test.espresso.matcher.RootMatchers.withDecorView;
import static android.support.test.espresso.matcher.ViewMatchers.hasDescendant;
import static android.support.test.espresso.matcher.ViewMatchers.hasFocus;
import static android.support.test.espresso.matcher.ViewMatchers.isAssignableFrom;
import static android.support.test.espresso.matcher.ViewMatchers.isDisplayed;
+import static android.support.test.espresso.matcher.ViewMatchers.isDisplayingAtLeast;
import static android.support.test.espresso.matcher.ViewMatchers.isEnabled;
import static android.support.test.espresso.matcher.ViewMatchers.withText;
+
import static org.hamcrest.Matchers.allOf;
import static org.hamcrest.Matchers.not;
-import com.android.internal.view.menu.ListMenuItemView;
-
import android.support.test.espresso.NoMatchingRootException;
import android.support.test.espresso.NoMatchingViewException;
import android.support.test.espresso.ViewInteraction;
import android.support.test.espresso.matcher.ViewMatchers;
+import android.view.View;
import android.widget.MenuPopupWindow.MenuDropDownListView;
+import com.android.internal.view.menu.ListMenuItemView;
+
+import org.hamcrest.Description;
+import org.hamcrest.Matcher;
+import org.hamcrest.TypeSafeMatcher;
+
/**
* Espresso utility methods for the context menu.
*/
@@ -82,10 +90,15 @@
private static void asssertContextMenuContainsItemWithEnabledState(String itemLabel,
boolean enabled) {
onContextMenu().check(matches(
- hasDescendant(allOf(
- isAssignableFrom(ListMenuItemView.class),
- enabled ? isEnabled() : not(isEnabled()),
- hasDescendant(withText(itemLabel))))));
+ hasDescendant(getVisibleMenuItemMatcher(itemLabel, enabled))));
+ }
+
+ private static Matcher<View> getVisibleMenuItemMatcher(String itemLabel, boolean enabled) {
+ return allOf(
+ isAssignableFrom(ListMenuItemView.class),
+ hasDescendant(withText(itemLabel)),
+ enabled ? isEnabled() : not(isEnabled()),
+ isDisplayingAtLeast(90));
}
/**
@@ -107,4 +120,70 @@
public static void assertContextMenuContainsItemDisabled(String itemLabel) {
asssertContextMenuContainsItemWithEnabledState(itemLabel, false);
}
+
+ /**
+ * Asserts that the context menu window is aligned to a given view with a given offset.
+ *
+ * @param anchor Anchor view.
+ * @param offsetX x offset
+ * @param offsetY y offset.
+ * @throws AssertionError if the assertion fails
+ */
+ public static void assertContextMenuAlignment(View anchor, int offsetX, int offsetY) {
+ int [] expectedLocation = new int[2];
+ anchor.getLocationOnScreen(expectedLocation);
+ expectedLocation[0] += offsetX;
+ expectedLocation[1] += offsetY;
+
+ final boolean rtl = anchor.getLayoutDirection() == View.LAYOUT_DIRECTION_RTL;
+
+ onContextMenu().check(matches(new TypeSafeMatcher<View>() {
+ @Override
+ public void describeTo(Description description) {
+ description.appendText("root view ");
+ description.appendText(rtl ? "right" : "left");
+ description.appendText("=");
+ description.appendText(Integer.toString(offsetX));
+ description.appendText(", top=");
+ description.appendText(Integer.toString(offsetY));
+ }
+
+ @Override
+ public boolean matchesSafely(View view) {
+ View rootView = view.getRootView();
+ int [] actualLocation = new int[2];
+ rootView.getLocationOnScreen(actualLocation);
+ if (rtl) {
+ actualLocation[0] += rootView.getWidth();
+ }
+ return expectedLocation[0] == actualLocation[0]
+ && expectedLocation[1] == actualLocation[1];
+ }
+ }));
+ }
+
+ /**
+ * Check is the menu item is clickable (i.e. visible and enabled).
+ *
+ * @param itemLabel Label of the item.
+ * @return True if the menu item is clickable.
+ */
+ public static boolean isMenuItemClickable(String itemLabel) {
+ try {
+ onContextMenu().check(matches(
+ hasDescendant(getVisibleMenuItemMatcher(itemLabel, true))));
+ return true;
+ } catch (NoMatchingRootException | NoMatchingViewException | AssertionError e) {
+ return false;
+ }
+ }
+
+ /**
+ * Click on a menu item with the specified label
+ * @param itemLabel Label of the item.
+ */
+ public static void clickMenuItem(String itemLabel) {
+ onView(getVisibleMenuItemMatcher(itemLabel, true))
+ .inRoot(withDecorView(hasFocus())).perform(click());
+ }
}
diff --git a/core/tests/coretests/src/com/android/internal/os/BatteryStatsNoteTest.java b/core/tests/coretests/src/com/android/internal/os/BatteryStatsNoteTest.java
index a55563a..82ac9da 100644
--- a/core/tests/coretests/src/com/android/internal/os/BatteryStatsNoteTest.java
+++ b/core/tests/coretests/src/com/android/internal/os/BatteryStatsNoteTest.java
@@ -23,10 +23,12 @@
import android.os.BatteryManager;
import android.os.BatteryStats;
import android.os.BatteryStats.HistoryItem;
+import android.os.BatteryStats.Uid.Sensor;
import android.os.WorkSource;
import android.support.test.filters.SmallTest;
import android.view.Display;
+import com.android.internal.os.BatteryStatsImpl.DualTimer;
import com.android.internal.os.BatteryStatsImpl.Uid;
import junit.framework.TestCase;
@@ -446,4 +448,52 @@
pkg = bi.getPackageStatsLocked(100, "com.foo.baz_alternate");
assertEquals(0, pkg.getWakeupAlarmStats().size());
}
+
+ @SmallTest
+ public void testNoteGpsChanged() {
+ final MockClocks clocks = new MockClocks(); // holds realtime and uptime in ms
+ MockBatteryStatsImpl bi = new MockBatteryStatsImpl(clocks);
+ bi.setRecordAllHistoryLocked(true);
+ bi.forceRecordAllHistory();
+ bi.mForceOnBattery = true;
+
+ bi.updateTimeBasesLocked(true, Display.STATE_OFF, 0, 0);
+ bi.noteUidProcessStateLocked(UID, ActivityManager.PROCESS_STATE_TOP);
+
+ WorkSource ws = new WorkSource();
+ ws.add(UID);
+
+ bi.noteGpsChangedLocked(new WorkSource(), ws);
+ DualTimer t = bi.getUidStatsLocked(UID).getSensorTimerLocked(Sensor.GPS, false);
+ assertNotNull(t);
+ assertTrue(t.isRunningLocked());
+
+ bi.noteGpsChangedLocked(ws, new WorkSource());
+ t = bi.getUidStatsLocked(UID).getSensorTimerLocked(Sensor.GPS, false);
+ assertFalse(t.isRunningLocked());
+ }
+
+ @SmallTest
+ public void testNoteGpsChanged_workSource() {
+ final MockClocks clocks = new MockClocks(); // holds realtime and uptime in ms
+ MockBatteryStatsImpl bi = new MockBatteryStatsImpl(clocks);
+ bi.setRecordAllHistoryLocked(true);
+ bi.forceRecordAllHistory();
+ bi.mForceOnBattery = true;
+
+ bi.updateTimeBasesLocked(true, Display.STATE_OFF, 0, 0);
+ bi.noteUidProcessStateLocked(UID, ActivityManager.PROCESS_STATE_TOP);
+
+ WorkSource ws = new WorkSource();
+ ws.createWorkChain().addNode(UID, "com.foo");
+
+ bi.noteGpsChangedLocked(new WorkSource(), ws);
+ DualTimer t = bi.getUidStatsLocked(UID).getSensorTimerLocked(Sensor.GPS, false);
+ assertNotNull(t);
+ assertTrue(t.isRunningLocked());
+
+ bi.noteGpsChangedLocked(ws, new WorkSource());
+ t = bi.getUidStatsLocked(UID).getSensorTimerLocked(Sensor.GPS, false);
+ assertFalse(t.isRunningLocked());
+ }
}
diff --git a/keystore/java/android/security/KeyStore.java b/keystore/java/android/security/KeyStore.java
index e25386b..ded427e 100644
--- a/keystore/java/android/security/KeyStore.java
+++ b/keystore/java/android/security/KeyStore.java
@@ -38,6 +38,7 @@
import android.security.keystore.KeyExpiredException;
import android.security.keystore.KeyNotYetValidException;
import android.security.keystore.KeyPermanentlyInvalidatedException;
+import android.security.keystore.StrongBoxUnavailableException;
import android.security.keystore.UserNotAuthenticatedException;
import android.util.Log;
@@ -65,6 +66,7 @@
public static final int VALUE_CORRUPTED = 8;
public static final int UNDEFINED_ACTION = 9;
public static final int WRONG_PASSWORD = 10;
+ public static final int HARDWARE_TYPE_UNAVAILABLE = -68;
/**
* Per operation authentication is needed before this operation is valid.
@@ -123,7 +125,6 @@
*/
public static final int FLAG_STRONGBOX = 1 << 4;
-
// States
public enum State { UNLOCKED, LOCKED, UNINITIALIZED };
@@ -730,6 +731,58 @@
}
}
+ // Keep in sync with confirmationui/1.0/types.hal.
+ public static final int CONFIRMATIONUI_OK = 0;
+ public static final int CONFIRMATIONUI_CANCELED = 1;
+ public static final int CONFIRMATIONUI_ABORTED = 2;
+ public static final int CONFIRMATIONUI_OPERATION_PENDING = 3;
+ public static final int CONFIRMATIONUI_IGNORED = 4;
+ public static final int CONFIRMATIONUI_SYSTEM_ERROR = 5;
+ public static final int CONFIRMATIONUI_UNIMPLEMENTED = 6;
+ public static final int CONFIRMATIONUI_UNEXPECTED = 7;
+ public static final int CONFIRMATIONUI_UIERROR = 0x10000;
+ public static final int CONFIRMATIONUI_UIERROR_MISSING_GLYPH = 0x10001;
+ public static final int CONFIRMATIONUI_UIERROR_MESSAGE_TOO_LONG = 0x10002;
+ public static final int CONFIRMATIONUI_UIERROR_MALFORMED_UTF8_ENCODING = 0x10003;
+
+ /**
+ * Requests keystore call into the confirmationui HAL to display a prompt.
+ *
+ * @param listener the binder to use for callbacks.
+ * @param promptText the prompt to display.
+ * @param extraData extra data / nonce from application.
+ * @param locale the locale as a BCP 47 langauge tag.
+ * @param uiOptionsAsFlags the UI options to use, as flags.
+ * @return one of the {@code CONFIRMATIONUI_*} constants, for
+ * example {@code KeyStore.CONFIRMATIONUI_OK}.
+ */
+ public int presentConfirmationPrompt(IBinder listener, String promptText, byte[] extraData,
+ String locale, int uiOptionsAsFlags) {
+ try {
+ return mBinder.presentConfirmationPrompt(listener, promptText, extraData, locale,
+ uiOptionsAsFlags);
+ } catch (RemoteException e) {
+ Log.w(TAG, "Cannot connect to keystore", e);
+ return CONFIRMATIONUI_SYSTEM_ERROR;
+ }
+ }
+
+ /**
+ * Requests keystore call into the confirmationui HAL to cancel displaying a prompt.
+ *
+ * @param listener the binder passed to the {@link #presentConfirmationPrompt} method.
+ * @return one of the {@code CONFIRMATIONUI_*} constants, for
+ * example {@code KeyStore.CONFIRMATIONUI_OK}.
+ */
+ public int cancelConfirmationPrompt(IBinder listener) {
+ try {
+ return mBinder.cancelConfirmationPrompt(listener);
+ } catch (RemoteException e) {
+ Log.w(TAG, "Cannot connect to keystore", e);
+ return CONFIRMATIONUI_SYSTEM_ERROR;
+ }
+ }
+
/**
* Returns a {@link KeyStoreException} corresponding to the provided keystore/keymaster error
* code.
diff --git a/keystore/java/android/security/keystore/AndroidKeyStoreKeyPairGeneratorSpi.java b/keystore/java/android/security/keystore/AndroidKeyStoreKeyPairGeneratorSpi.java
index dba3949..d1eb688 100644
--- a/keystore/java/android/security/keystore/AndroidKeyStoreKeyPairGeneratorSpi.java
+++ b/keystore/java/android/security/keystore/AndroidKeyStoreKeyPairGeneratorSpi.java
@@ -21,6 +21,7 @@
import android.security.GateKeeper;
import android.security.KeyPairGeneratorSpec;
import android.security.KeyStore;
+import android.security.KeyStoreException;
import android.security.keymaster.KeyCharacteristics;
import android.security.keymaster.KeymasterArguments;
import android.security.keymaster.KeymasterCertificateChain;
@@ -451,7 +452,7 @@
throw new IllegalStateException("Not initialized");
}
- final int flags = (mEncryptionAtRestRequired) ? KeyStore.FLAG_ENCRYPTED : 0;
+ int flags = (mEncryptionAtRestRequired) ? KeyStore.FLAG_ENCRYPTED : 0;
if (((flags & KeyStore.FLAG_ENCRYPTED) != 0)
&& (mKeyStore.state() != KeyStore.State.UNLOCKED)) {
throw new IllegalStateException(
@@ -459,6 +460,10 @@
+ ", but the user has not yet entered the credential");
}
+ if (mSpec.isStrongBoxBacked()) {
+ flags |= KeyStore.FLAG_STRONGBOX;
+ }
+
byte[] additionalEntropy =
KeyStoreCryptoOperationUtils.getRandomBytesToMixIntoKeystoreRng(
mRng, (mKeySizeBits + 7) / 8);
@@ -501,8 +506,12 @@
int errorCode = mKeyStore.generateKey(privateKeyAlias, args, additionalEntropy,
mEntryUid, flags, resultingKeyCharacteristics);
if (errorCode != KeyStore.NO_ERROR) {
- throw new ProviderException(
- "Failed to generate key pair", KeyStore.getKeyStoreException(errorCode));
+ if (errorCode == KeyStore.HARDWARE_TYPE_UNAVAILABLE) {
+ throw new StrongBoxUnavailableException("Failed to generate key pair");
+ } else {
+ throw new ProviderException(
+ "Failed to generate key pair", KeyStore.getKeyStoreException(errorCode));
+ }
}
}
diff --git a/keystore/java/android/security/keystore/StrongBoxUnavailableException.java b/keystore/java/android/security/keystore/StrongBoxUnavailableException.java
index ad41a58..66a77ed 100644
--- a/keystore/java/android/security/keystore/StrongBoxUnavailableException.java
+++ b/keystore/java/android/security/keystore/StrongBoxUnavailableException.java
@@ -16,6 +16,9 @@
package android.security.keystore;
+import android.security.KeyStore;
+import android.security.KeyStoreException;
+
import java.security.ProviderException;
/**
@@ -24,5 +27,13 @@
*/
public class StrongBoxUnavailableException extends ProviderException {
+ /**
+ * @hide
+ */
+ public StrongBoxUnavailableException(String message) {
+ super(message,
+ new KeyStoreException(KeyStore.HARDWARE_TYPE_UNAVAILABLE, "No StrongBox available")
+ );
+ }
}
diff --git a/media/java/android/media/AudioRecord.java b/media/java/android/media/AudioRecord.java
index 27784e9..eb6e830 100644
--- a/media/java/android/media/AudioRecord.java
+++ b/media/java/android/media/AudioRecord.java
@@ -32,6 +32,7 @@
import android.os.IBinder;
import android.os.Looper;
import android.os.Message;
+import android.os.PersistableBundle;
import android.os.RemoteException;
import android.os.ServiceManager;
import android.util.ArrayMap;
@@ -1314,6 +1315,23 @@
return native_read_in_direct_buffer(audioBuffer, sizeInBytes, readMode == READ_BLOCKING);
}
+ /**
+ * Return Metrics data about the current AudioTrack instance.
+ *
+ * @return a {@link PersistableBundle} containing the set of attributes and values
+ * available for the media being handled by this instance of AudioRecord
+ * The attributes are descibed in {@link MetricsConstants}.
+ *
+ * Additional vendor-specific fields may also be present in
+ * the return value.
+ */
+ public PersistableBundle getMetrics() {
+ PersistableBundle bundle = native_getMetrics();
+ return bundle;
+ }
+
+ private native PersistableBundle native_getMetrics();
+
//--------------------------------------------------------------------------
// Initialization / configuration
//--------------------
@@ -1739,4 +1757,46 @@
private static void loge(String msg) {
Log.e(TAG, msg);
}
+
+ public static final class MetricsConstants
+ {
+ private MetricsConstants() {}
+
+ /**
+ * Key to extract the output format being recorded
+ * from the {@link AudioRecord#getMetrics} return value.
+ * The value is a String.
+ */
+ public static final String ENCODING = "android.media.audiorecord.encoding";
+
+ /**
+ * Key to extract the Source Type for this track
+ * from the {@link AudioRecord#getMetrics} return value.
+ * The value is a String.
+ */
+ public static final String SOURCE = "android.media.audiorecord.source";
+
+ /**
+ * Key to extract the estimated latency through the recording pipeline
+ * from the {@link AudioRecord#getMetrics} return value.
+ * This is in units of milliseconds.
+ * The value is an integer.
+ */
+ public static final String LATENCY = "android.media.audiorecord.latency";
+
+ /**
+ * Key to extract the sink sample rate for this record track in Hz
+ * from the {@link AudioRecord#getMetrics} return value.
+ * The value is an integer.
+ */
+ public static final String SAMPLERATE = "android.media.audiorecord.samplerate";
+
+ /**
+ * Key to extract the number of channels being recorded in this record track
+ * from the {@link AudioRecord#getMetrics} return value.
+ * The value is an integer.
+ */
+ public static final String CHANNELS = "android.media.audiorecord.channels";
+
+ }
}
diff --git a/media/java/android/media/AudioTrack.java b/media/java/android/media/AudioTrack.java
index 5928d03..4e9ce8e 100644
--- a/media/java/android/media/AudioTrack.java
+++ b/media/java/android/media/AudioTrack.java
@@ -36,6 +36,7 @@
import android.os.IBinder;
import android.os.Looper;
import android.os.Message;
+import android.os.PersistableBundle;
import android.os.Process;
import android.os.RemoteException;
import android.os.ServiceManager;
@@ -1718,6 +1719,23 @@
return ret;
}
+ /**
+ * Return Metrics data about the current AudioTrack instance.
+ *
+ * @return a {@link PersistableBundle} containing the set of attributes and values
+ * available for the media being handled by this instance of AudioTrack
+ * The attributes are descibed in {@link MetricsConstants}.
+ *
+ * Additional vendor-specific fields may also be present in
+ * the return value.
+ */
+ public PersistableBundle getMetrics() {
+ PersistableBundle bundle = native_getMetrics();
+ return bundle;
+ }
+
+ private native PersistableBundle native_getMetrics();
+
//--------------------------------------------------------------------------
// Initialization / configuration
//--------------------
@@ -3239,4 +3257,46 @@
private static void loge(String msg) {
Log.e(TAG, msg);
}
+
+ public final static class MetricsConstants
+ {
+ private MetricsConstants() {}
+
+ /**
+ * Key to extract the Stream Type for this track
+ * from the {@link AudioTrack#getMetrics} return value.
+ * The value is a String.
+ */
+ public static final String STREAMTYPE = "android.media.audiotrack.streamtype";
+
+ /**
+ * Key to extract the Content Type for this track
+ * from the {@link AudioTrack#getMetrics} return value.
+ * The value is a String.
+ */
+ public static final String CONTENTTYPE = "android.media.audiotrack.type";
+
+ /**
+ * Key to extract the Content Type for this track
+ * from the {@link AudioTrack#getMetrics} return value.
+ * The value is a String.
+ */
+ public static final String USAGE = "android.media.audiotrack.usage";
+
+ /**
+ * Key to extract the sample rate for this track in Hz
+ * from the {@link AudioTrack#getMetrics} return value.
+ * The value is an integer.
+ */
+ public static final String SAMPLERATE = "android.media.audiorecord.samplerate";
+
+ /**
+ * Key to extract the channel mask information for this track
+ * from the {@link AudioTrack#getMetrics} return value.
+ *
+ * The value is a Long integer.
+ */
+ public static final String CHANNELMASK = "android.media.audiorecord.channelmask";
+
+ }
}
diff --git a/media/java/android/media/MediaBrowser2.java b/media/java/android/media/MediaBrowser2.java
index be4be3f..5ad4313 100644
--- a/media/java/android/media/MediaBrowser2.java
+++ b/media/java/android/media/MediaBrowser2.java
@@ -16,8 +16,10 @@
package android.media;
+import android.annotation.CallbackExecutor;
import android.annotation.NonNull;
import android.annotation.Nullable;
+import android.annotation.SystemApi;
import android.content.Context;
import android.media.update.ApiLoader;
import android.media.update.MediaBrowser2Provider;
@@ -99,17 +101,17 @@
@Nullable Bundle options, @Nullable List<MediaItem2> result) { }
}
- public MediaBrowser2(Context context, SessionToken2 token, BrowserCallback callback,
- Executor executor) {
- super(context, token, callback, executor);
+ public MediaBrowser2(@NonNull Context context, @NonNull SessionToken2 token,
+ @NonNull @CallbackExecutor Executor executor, @NonNull BrowserCallback callback) {
+ super(context, token, executor, callback);
mProvider = (MediaBrowser2Provider) getProvider();
}
@Override
MediaBrowser2Provider createProvider(Context context, SessionToken2 token,
- ControllerCallback callback, Executor executor) {
+ Executor executor, ControllerCallback callback) {
return ApiLoader.getProvider(context)
- .createMediaBrowser2(this, context, token, (BrowserCallback) callback, executor);
+ .createMediaBrowser2(context, this, token, executor, (BrowserCallback) callback);
}
public void getBrowserRoot(Bundle rootHints) {
diff --git a/media/java/android/media/MediaController2.java b/media/java/android/media/MediaController2.java
index d669bc1..6064ec4 100644
--- a/media/java/android/media/MediaController2.java
+++ b/media/java/android/media/MediaController2.java
@@ -16,15 +16,17 @@
package android.media;
+import android.annotation.CallbackExecutor;
import android.annotation.NonNull;
import android.annotation.Nullable;
+import android.annotation.SystemApi;
import android.app.PendingIntent;
import android.content.Context;
import android.media.MediaSession2.Command;
import android.media.MediaSession2.CommandButton;
import android.media.MediaSession2.CommandGroup;
import android.media.MediaSession2.ControllerInfo;
-import android.media.MediaSession2.PlaylistParam;
+import android.media.MediaSession2.PlaylistParams;
import android.media.session.MediaSessionManager;
import android.media.update.ApiLoader;
import android.media.update.MediaController2Provider;
@@ -63,8 +65,6 @@
* @see MediaSessionService2
* @hide
*/
-// TODO(jaewan): Unhide
-// TODO(jaewan): Revisit comments. Currently MediaBrowser case is missing.
public class MediaController2 implements AutoCloseable {
/**
* Interface for listening to change in activeness of the {@link MediaSession2}. It's
@@ -130,7 +130,7 @@
* @param param
*/
public void onPlaylistChanged(
- @NonNull List<MediaItem2> list, @NonNull PlaylistParam param) { }
+ @NonNull List<MediaItem2> list, @NonNull PlaylistParams param) { }
/**
* Called when the playback state is changed.
@@ -239,12 +239,12 @@
*
* @param context Context
* @param token token to connect to
- * @param callback controller callback to receive changes in
* @param executor executor to run callbacks on.
+ * @param callback controller callback to receive changes in
*/
// TODO(jaewan): Put @CallbackExecutor to the constructor.
public MediaController2(@NonNull Context context, @NonNull SessionToken2 token,
- @NonNull ControllerCallback callback, @NonNull Executor executor) {
+ @NonNull @CallbackExecutor Executor executor, @NonNull ControllerCallback callback) {
super();
// This also connects to the token.
@@ -252,14 +252,14 @@
// session whose session binder is only valid while it's active.
// prevent a controller from reusable after the
// session is released and recreated.
- mProvider = createProvider(context, token, callback, executor);
+ mProvider = createProvider(context, token, executor, callback);
}
MediaController2Provider createProvider(@NonNull Context context,
- @NonNull SessionToken2 token, @NonNull ControllerCallback callback,
- @NonNull Executor executor) {
+ @NonNull SessionToken2 token, @NonNull Executor executor,
+ @NonNull ControllerCallback callback) {
return ApiLoader.getProvider(context)
- .createMediaController2(this, context, token, callback, executor);
+ .createMediaController2(context, this, token, executor, callback);
}
/**
@@ -271,9 +271,7 @@
mProvider.close_impl();
}
- /**
- * @hide
- */
+ @SystemApi
public MediaController2Provider getProvider() {
return mProvider;
}
@@ -578,7 +576,8 @@
return mProvider.getPlaylist_impl();
}
- public @Nullable PlaylistParam getPlaylistParam() {
+ public @Nullable
+ PlaylistParams getPlaylistParam() {
return mProvider.getPlaylistParam_impl();
}
diff --git a/media/java/android/media/MediaDrm.java b/media/java/android/media/MediaDrm.java
index 844f2ef..a0edefa 100644
--- a/media/java/android/media/MediaDrm.java
+++ b/media/java/android/media/MediaDrm.java
@@ -1253,8 +1253,6 @@
*
* Additional vendor-specific fields may also be present in
* the return value.
- *
- * @hide - not part of the public API at this time
*/
public PersistableBundle getMetrics() {
PersistableBundle bundle = getMetricsNative();
@@ -1571,8 +1569,6 @@
/**
* Definitions for the metrics that are reported via the
* {@link #getMetrics} call.
- *
- * @hide - not part of the public API at this time
*/
public final static class MetricsConstants
{
@@ -1585,7 +1581,7 @@
* The count is a Long value ({@link android.os.BaseBundle#getLong}).
*/
public static final String OPEN_SESSION_OK_COUNT
- = "/drm/mediadrm/open_session/ok/count";
+ = "drm.mediadrm.open_session.ok.count";
/**
* Key to extract the number of failed {@link #openSession} calls
@@ -1594,7 +1590,7 @@
* The count is a Long value ({@link android.os.BaseBundle#getLong}).
*/
public static final String OPEN_SESSION_ERROR_COUNT
- = "/drm/mediadrm/open_session/error/count";
+ = "drm.mediadrm.open_session.error.count";
/**
* Key to extract the list of error codes that were returned from
@@ -1605,7 +1601,7 @@
* ({@link android.os.BaseBundle#getLongArray}).
*/
public static final String OPEN_SESSION_ERROR_LIST
- = "/drm/mediadrm/open_session/error/list";
+ = "drm.mediadrm.open_session.error.list";
/**
* Key to extract the number of successful {@link #closeSession} calls
@@ -1614,7 +1610,7 @@
* The count is a Long value ({@link android.os.BaseBundle#getLong}).
*/
public static final String CLOSE_SESSION_OK_COUNT
- = "/drm/mediadrm/close_session/ok/count";
+ = "drm.mediadrm.close_session.ok.count";
/**
* Key to extract the number of failed {@link #closeSession} calls
@@ -1623,7 +1619,7 @@
* The count is a Long value ({@link android.os.BaseBundle#getLong}).
*/
public static final String CLOSE_SESSION_ERROR_COUNT
- = "/drm/mediadrm/close_session/error/count";
+ = "drm.mediadrm.close_session.error.count";
/**
* Key to extract the list of error codes that were returned from
@@ -1634,7 +1630,7 @@
* ({@link android.os.BaseBundle#getLongArray}).
*/
public static final String CLOSE_SESSION_ERROR_LIST
- = "/drm/mediadrm/close_session/error/list";
+ = "drm.mediadrm.close_session.error.list";
/**
* Key to extract the start times of sessions. Times are
@@ -1648,7 +1644,7 @@
* the start time for each session.
*/
public static final String SESSION_START_TIMES_MS
- = "/drm/mediadrm/session_start_times_ms";
+ = "drm.mediadrm.session_start_times_ms";
/**
* Key to extract the end times of sessions. Times are
@@ -1662,7 +1658,7 @@
* the end time for each session.
*/
public static final String SESSION_END_TIMES_MS
- = "/drm/mediadrm/session_end_times_ms";
+ = "drm.mediadrm.session_end_times_ms";
/**
* Key to extract the number of successful {@link #getKeyRequest} calls
@@ -1671,7 +1667,7 @@
* The count is a Long value ({@link android.os.BaseBundle#getLong}).
*/
public static final String GET_KEY_REQUEST_OK_COUNT
- = "/drm/mediadrm/get_key_request/ok/count";
+ = "drm.mediadrm.get_key_request.ok.count";
/**
* Key to extract the number of failed {@link #getKeyRequest}
@@ -1680,7 +1676,7 @@
* The count is a Long value ({@link android.os.BaseBundle#getLong}).
*/
public static final String GET_KEY_REQUEST_ERROR_COUNT
- = "/drm/mediadrm/get_key_request/error/count";
+ = "drm.mediadrm.get_key_request.error.count";
/**
* Key to extract the list of error codes that were returned from
@@ -1691,7 +1687,7 @@
* ({@link android.os.BaseBundle#getLongArray}).
*/
public static final String GET_KEY_REQUEST_ERROR_LIST
- = "/drm/mediadrm/get_key_request/error/list";
+ = "drm.mediadrm.get_key_request.error.list";
/**
* Key to extract the average time in microseconds of calls to
@@ -1700,7 +1696,7 @@
* The time is a Long value ({@link android.os.BaseBundle#getLong}).
*/
public static final String GET_KEY_REQUEST_OK_TIME_MICROS
- = "/drm/mediadrm/get_key_request/ok/average_time_micros";
+ = "drm.mediadrm.get_key_request.ok.average_time_micros";
/**
* Key to extract the number of successful {@link #provideKeyResponse}
@@ -1709,7 +1705,7 @@
* The count is a Long value ({@link android.os.BaseBundle#getLong}).
*/
public static final String PROVIDE_KEY_RESPONSE_OK_COUNT
- = "/drm/mediadrm/provide_key_response/ok/count";
+ = "drm.mediadrm.provide_key_response.ok.count";
/**
* Key to extract the number of failed {@link #provideKeyResponse}
@@ -1718,7 +1714,7 @@
* The count is a Long value ({@link android.os.BaseBundle#getLong}).
*/
public static final String PROVIDE_KEY_RESPONSE_ERROR_COUNT
- = "/drm/mediadrm/provide_key_response/error/count";
+ = "drm.mediadrm.provide_key_response.error.count";
/**
* Key to extract the list of error codes that were returned from
@@ -1729,7 +1725,7 @@
* ({@link android.os.BaseBundle#getLongArray}).
*/
public static final String PROVIDE_KEY_RESPONSE_ERROR_LIST
- = "/drm/mediadrm/provide_key_response/error/list";
+ = "drm.mediadrm.provide_key_response.error.list";
/**
* Key to extract the average time in microseconds of calls to
@@ -1738,7 +1734,7 @@
* The time is a Long value ({@link android.os.BaseBundle#getLong}).
*/
public static final String PROVIDE_KEY_RESPONSE_OK_TIME_MICROS
- = "/drm/mediadrm/provide_key_response/ok/average_time_micros";
+ = "drm.mediadrm.provide_key_response.ok.average_time_micros";
/**
* Key to extract the number of successful {@link #getProvisionRequest}
@@ -1747,7 +1743,7 @@
* The count is a Long value ({@link android.os.BaseBundle#getLong}).
*/
public static final String GET_PROVISION_REQUEST_OK_COUNT
- = "/drm/mediadrm/get_provision_request/ok/count";
+ = "drm.mediadrm.get_provision_request.ok.count";
/**
* Key to extract the number of failed {@link #getProvisionRequest}
@@ -1756,7 +1752,7 @@
* The count is a Long value ({@link android.os.BaseBundle#getLong}).
*/
public static final String GET_PROVISION_REQUEST_ERROR_COUNT
- = "/drm/mediadrm/get_provision_request/error/count";
+ = "drm.mediadrm.get_provision_request.error.count";
/**
* Key to extract the list of error codes that were returned from
@@ -1767,7 +1763,7 @@
* ({@link android.os.BaseBundle#getLongArray}).
*/
public static final String GET_PROVISION_REQUEST_ERROR_LIST
- = "/drm/mediadrm/get_provision_request/error/list";
+ = "drm.mediadrm.get_provision_request.error.list";
/**
* Key to extract the number of successful
@@ -1776,7 +1772,7 @@
* The count is a Long value ({@link android.os.BaseBundle#getLong}).
*/
public static final String PROVIDE_PROVISION_RESPONSE_OK_COUNT
- = "/drm/mediadrm/provide_provision_response/ok/count";
+ = "drm.mediadrm.provide_provision_response.ok.count";
/**
* Key to extract the number of failed
@@ -1785,7 +1781,7 @@
* The count is a Long value ({@link android.os.BaseBundle#getLong}).
*/
public static final String PROVIDE_PROVISION_RESPONSE_ERROR_COUNT
- = "/drm/mediadrm/provide_provision_response/error/count";
+ = "drm.mediadrm.provide_provision_response.error.count";
/**
* Key to extract the list of error codes that were returned from
@@ -1796,7 +1792,7 @@
* ({@link android.os.BaseBundle#getLongArray}).
*/
public static final String PROVIDE_PROVISION_RESPONSE_ERROR_LIST
- = "/drm/mediadrm/provide_provision_response/error/list";
+ = "drm.mediadrm.provide_provision_response.error.list";
/**
* Key to extract the number of successful
@@ -1807,7 +1803,7 @@
* The count is a Long value ({@link android.os.BaseBundle#getLong}).
*/
public static final String GET_DEVICE_UNIQUE_ID_OK_COUNT
- = "/drm/mediadrm/get_device_unique_id/ok/count";
+ = "drm.mediadrm.get_device_unique_id.ok.count";
/**
* Key to extract the number of failed
@@ -1818,7 +1814,7 @@
* The count is a Long value ({@link android.os.BaseBundle#getLong}).
*/
public static final String GET_DEVICE_UNIQUE_ID_ERROR_COUNT
- = "/drm/mediadrm/get_device_unique_id/error/count";
+ = "drm.mediadrm.get_device_unique_id.error.count";
/**
* Key to extract the list of error codes that were returned from
@@ -1830,7 +1826,7 @@
* ({@link android.os.BaseBundle#getLongArray}).
*/
public static final String GET_DEVICE_UNIQUE_ID_ERROR_LIST
- = "/drm/mediadrm/get_device_unique_id/error/list";
+ = "drm.mediadrm.get_device_unique_id.error.list";
/**
* Key to extraact the count of {@link KeyStatus#STATUS_EXPIRED} events
@@ -1839,7 +1835,7 @@
* The count is a Long value ({@link android.os.BaseBundle#getLong}).
*/
public static final String KEY_STATUS_EXPIRED_COUNT
- = "/drm/mediadrm/key_status/EXPIRED/count";
+ = "drm.mediadrm.key_status.EXPIRED.count";
/**
* Key to extract the count of {@link KeyStatus#STATUS_INTERNAL_ERROR}
@@ -1848,7 +1844,7 @@
* The count is a Long value ({@link android.os.BaseBundle#getLong}).
*/
public static final String KEY_STATUS_INTERNAL_ERROR_COUNT
- = "/drm/mediadrm/key_status/INTERNAL_ERROR/count";
+ = "drm.mediadrm.key_status.INTERNAL_ERROR.count";
/**
* Key to extract the count of
@@ -1858,7 +1854,7 @@
* The count is a Long value ({@link android.os.BaseBundle#getLong}).
*/
public static final String KEY_STATUS_OUTPUT_NOT_ALLOWED_COUNT
- = "/drm/mediadrm/key_status_change/OUTPUT_NOT_ALLOWED/count";
+ = "drm.mediadrm.key_status_change.OUTPUT_NOT_ALLOWED.count";
/**
* Key to extract the count of {@link KeyStatus#STATUS_PENDING}
@@ -1867,7 +1863,7 @@
* The count is a Long value ({@link android.os.BaseBundle#getLong}).
*/
public static final String KEY_STATUS_PENDING_COUNT
- = "/drm/mediadrm/key_status_change/PENDING/count";
+ = "drm.mediadrm.key_status_change.PENDING.count";
/**
* Key to extract the count of {@link KeyStatus#STATUS_USABLE}
@@ -1876,7 +1872,7 @@
* The count is a Long value ({@link android.os.BaseBundle#getLong}).
*/
public static final String KEY_STATUS_USABLE_COUNT
- = "/drm/mediadrm/key_status_change/USABLE/count";
+ = "drm.mediadrm.key_status_change.USABLE.count";
/**
* Key to extract the count of {@link OnEventListener#onEvent}
@@ -1886,7 +1882,7 @@
* The count is a Long value ({@link android.os.BaseBundle#getLong}).
*/
public static final String EVENT_PROVISION_REQUIRED_COUNT
- = "/drm/mediadrm/event/PROVISION_REQUIRED/count";
+ = "drm.mediadrm.event.PROVISION_REQUIRED.count";
/**
* Key to extract the count of {@link OnEventListener#onEvent}
@@ -1896,7 +1892,7 @@
* The count is a Long value ({@link android.os.BaseBundle#getLong}).
*/
public static final String EVENT_KEY_NEEDED_COUNT
- = "/drm/mediadrm/event/KEY_NEEDED/count";
+ = "drm.mediadrm.event.KEY_NEEDED.count";
/**
* Key to extract the count of {@link OnEventListener#onEvent}
@@ -1906,7 +1902,7 @@
* The count is a Long value ({@link android.os.BaseBundle#getLong}).
*/
public static final String EVENT_KEY_EXPIRED_COUNT
- = "/drm/mediadrm/event/KEY_EXPIRED/count";
+ = "drm.mediadrm.event.KEY_EXPIRED.count";
/**
* Key to extract the count of {@link OnEventListener#onEvent}
@@ -1916,7 +1912,7 @@
* The count is a Long value ({@link android.os.BaseBundle#getLong}).
*/
public static final String EVENT_VENDOR_DEFINED_COUNT
- = "/drm/mediadrm/event/VENDOR_DEFINED/count";
+ = "drm.mediadrm.event.VENDOR_DEFINED.count";
/**
* Key to extract the count of {@link OnEventListener#onEvent}
@@ -1926,6 +1922,6 @@
* The count is a Long value ({@link android.os.BaseBundle#getLong}).
*/
public static final String EVENT_SESSION_RECLAIMED_COUNT
- = "/drm/mediadrm/event/SESSION_RECLAIMED/count";
+ = "drm.mediadrm.event.SESSION_RECLAIMED.count";
}
}
diff --git a/media/java/android/media/MediaExtractor.java b/media/java/android/media/MediaExtractor.java
index 2c1b4b3..174d6a3 100644
--- a/media/java/android/media/MediaExtractor.java
+++ b/media/java/android/media/MediaExtractor.java
@@ -626,6 +626,12 @@
*/
public native long getSampleTime();
+ /**
+ * @return size of the current sample in bytes or -1 if no more
+ * samples are available.
+ */
+ public native long getSampleSize();
+
// Keep these in sync with their equivalents in NuMediaExtractor.h
/**
* The sample is a sync sample (or in {@link MediaCodec}'s terminology
diff --git a/media/java/android/media/MediaItem2.java b/media/java/android/media/MediaItem2.java
index 96a87d5..6a96faa 100644
--- a/media/java/android/media/MediaItem2.java
+++ b/media/java/android/media/MediaItem2.java
@@ -19,6 +19,7 @@
import android.annotation.IntDef;
import android.annotation.NonNull;
import android.annotation.Nullable;
+import android.annotation.SystemApi;
import android.os.Bundle;
import android.text.TextUtils;
@@ -32,15 +33,10 @@
* When it's sent to a controller or browser, it's anonymized and data descriptor wouldn't be sent.
* <p>
* This object isn't a thread safe.
- *
* @hide
*/
-// TODO(jaewan): Unhide and extends from DataSourceDesc.
-// Note) Feels like an anti-pattern. We should anonymize MediaItem2 to remove *all*
-// information in the DataSourceDesc. Why it should extends from this?
-// TODO(jaewan): Move this to updatable
-// Previously MediaBrowser.MediaItem
public class MediaItem2 {
+ // TODO(jaewan): Keep DataSourceDesc.
private final int mFlags;
private MediaMetadata2 mMetadata;
diff --git a/media/java/android/media/MediaLibraryService2.java b/media/java/android/media/MediaLibraryService2.java
index d7e43ec..5dadcb5 100644
--- a/media/java/android/media/MediaLibraryService2.java
+++ b/media/java/android/media/MediaLibraryService2.java
@@ -28,7 +28,6 @@
import android.media.update.MediaSession2Provider;
import android.media.update.MediaSessionService2Provider;
import android.os.Bundle;
-import android.service.media.MediaBrowserService.BrowserRoot;
import java.util.List;
import java.util.concurrent.Executor;
@@ -54,7 +53,6 @@
* declare metadata in the manifest as follows.
* @hide
*/
-// TODO(jaewan): Unhide
public abstract class MediaLibraryService2 extends MediaSessionService2 {
/**
* This is the interface name that a service implementing a session service should say that it
@@ -69,21 +67,21 @@
private final MediaLibrarySessionProvider mProvider;
MediaLibrarySession(Context context, MediaPlayerBase player, String id,
- Executor callbackExecutor, SessionCallback callback, VolumeProvider volumeProvider,
- int ratingType, PendingIntent sessionActivity) {
- super(context, player, id, callbackExecutor, callback, volumeProvider, ratingType,
- sessionActivity);
+ VolumeProvider volumeProvider, int ratingType, PendingIntent sessionActivity,
+ Executor callbackExecutor, SessionCallback callback) {
+ super(context, player, id, volumeProvider, ratingType, sessionActivity,
+ callbackExecutor, callback);
mProvider = (MediaLibrarySessionProvider) getProvider();
}
@Override
MediaSession2Provider createProvider(Context context, MediaPlayerBase player, String id,
- Executor callbackExecutor, SessionCallback callback, VolumeProvider volumeProvider,
- int ratingType, PendingIntent sessionActivity) {
+ VolumeProvider volumeProvider, int ratingType, PendingIntent sessionActivity,
+ Executor callbackExecutor, SessionCallback callback) {
return ApiLoader.getProvider(context)
- .createMediaLibraryService2MediaLibrarySession(this, context, player, id,
- callbackExecutor, (MediaLibrarySessionCallback) callback,
- volumeProvider, ratingType, sessionActivity);
+ .createMediaLibraryService2MediaLibrarySession(context, this, player, id,
+ volumeProvider, ratingType, sessionActivity,
+ callbackExecutor, (MediaLibrarySessionCallback) callback);
}
/**
@@ -226,9 +224,9 @@
}
@Override
- public MediaLibrarySession build() throws IllegalStateException {
- return new MediaLibrarySession(mContext, mPlayer, mId, mCallbackExecutor, mCallback,
- mVolumeProvider, mRatingType, mSessionActivity);
+ public MediaLibrarySession build() {
+ return new MediaLibrarySession(mContext, mPlayer, mId, mVolumeProvider, mRatingType,
+ mSessionActivity, mCallbackExecutor, mCallback);
}
}
@@ -277,7 +275,7 @@
* @see #EXTRA_OFFLINE
* @see #EXTRA_SUGGESTED
*/
- public static final String EXTRA_RECENT = "android.service.media.extra.RECENT";
+ public static final String EXTRA_RECENT = "android.media.extra.RECENT";
/**
* The lookup key for a boolean that indicates whether the browser service should return a
@@ -295,7 +293,7 @@
* @see #EXTRA_RECENT
* @see #EXTRA_SUGGESTED
*/
- public static final String EXTRA_OFFLINE = "android.service.media.extra.OFFLINE";
+ public static final String EXTRA_OFFLINE = "android.media.extra.OFFLINE";
/**
* The lookup key for a boolean that indicates whether the browser service should return a
@@ -303,8 +301,8 @@
*
* <p>When creating a media browser for a given media browser service, this key can be
* supplied as a root hint for retrieving the media items suggested by the media browser
- * service. The list of media items passed in {@link android.media.browse.MediaBrowser.SubscriptionCallback#onChildrenLoaded(String, List)}
- * is considered ordered by relevance, first being the top suggestion.
+ * service. The list of media items is considered ordered by relevance, first being the top
+ * suggestion.
* If the media browser service can provide such media items, the implementation must return
* the key in the root hint when
* {@link MediaLibrarySessionCallback#onGetRoot(ControllerInfo, Bundle)} is called back.
@@ -314,7 +312,7 @@
* @see #EXTRA_RECENT
* @see #EXTRA_OFFLINE
*/
- public static final String EXTRA_SUGGESTED = "android.service.media.extra.SUGGESTED";
+ public static final String EXTRA_SUGGESTED = "android.media.extra.SUGGESTED";
final private String mRootId;
final private Bundle mExtras;
diff --git a/media/java/android/media/MediaMetadata2.java b/media/java/android/media/MediaMetadata2.java
index 0e24db6..fcdb4f7 100644
--- a/media/java/android/media/MediaMetadata2.java
+++ b/media/java/android/media/MediaMetadata2.java
@@ -34,6 +34,7 @@
/**
* Contains metadata about an item, such as the title, artist, etc.
+ *
* @hide
*/
// TODO(jaewan): Move this to updatable
@@ -218,7 +219,7 @@
/**
* A Uri formatted String representing the content. This value is specific to the
* service providing the content. It may be used with
- * {@link MediaController2#playFromUri(Uri, Bundle)}
+ * {@link MediaController2#playFromUri(String, Bundle)}
* to initiate playback when provided by a {@link MediaBrowser2} connected to
* the same app.
*/
diff --git a/media/java/android/media/MediaPlayerBase.java b/media/java/android/media/MediaPlayerBase.java
index d638a9f..0efec901 100644
--- a/media/java/android/media/MediaPlayerBase.java
+++ b/media/java/android/media/MediaPlayerBase.java
@@ -16,16 +16,13 @@
package android.media;
-import android.media.MediaSession2.PlaylistParam;
-import android.media.session.PlaybackState;
-import android.os.Handler;
+import android.media.MediaSession2.PlaylistParams;
import java.util.List;
import java.util.concurrent.Executor;
/**
* Base interfaces for all media players that want media session.
- *
* @hide
*/
public abstract class MediaPlayerBase {
@@ -52,7 +49,7 @@
public abstract PlaybackState2 getPlaybackState();
public abstract AudioAttributes getAudioAttributes();
- public abstract void setPlaylist(List<MediaItem2> item, PlaylistParam param);
+ public abstract void setPlaylist(List<MediaItem2> item, PlaylistParams param);
public abstract void setCurrentPlaylistItem(int index);
/**
diff --git a/media/java/android/media/MediaSession2.java b/media/java/android/media/MediaSession2.java
index 0e90040..7dffd40 100644
--- a/media/java/android/media/MediaSession2.java
+++ b/media/java/android/media/MediaSession2.java
@@ -20,7 +20,7 @@
import android.annotation.IntDef;
import android.annotation.NonNull;
import android.annotation.Nullable;
-import android.app.Activity;
+import android.annotation.SystemApi;
import android.app.PendingIntent;
import android.content.Context;
import android.content.Intent;
@@ -77,12 +77,6 @@
* @see MediaSessionService2
* @hide
*/
-// TODO(jaewan): Unhide
-// TODO(jaewan): Revisit comments. Currently it's borrowed from the MediaSession.
-// TODO(jaewan): Should we support thread safe? It may cause tricky issue such as b/63797089
-// TODO(jaewan): Should we make APIs for MediaSessionService2 public? It's helpful for
-// developers that doesn't want to override from Browser, but user may not use this
-// correctly.
public class MediaSession2 implements AutoCloseable {
private final MediaSession2Provider mProvider;
@@ -349,7 +343,8 @@
/**
* Called when a controller set rating on the currently playing contents.
*
- * @param
+ * @param controller controller information
+ * @param rating new rating from the controller
*/
public void onSetRating(@NonNull ControllerInfo controller, @NonNull Rating2 rating) { }
@@ -429,7 +424,7 @@
/**
* Override to handle requests to play a specific media item represented by a URI.
*/
- public void prepareFromUri(@NonNull ControllerInfo controller,
+ public void onPrepareFromUri(@NonNull ControllerInfo controller,
@NonNull Uri uri, @Nullable Bundle extras) { }
/**
@@ -527,7 +522,7 @@
/**
* Set an intent for launching UI for this Session. This can be used as a
* quick link to an ongoing media screen. The intent should be for an
- * activity that may be started using {@link Activity#startActivity(Intent)}.
+ * activity that may be started using {@link Context#startActivity(Intent)}.
*
* @param pi The intent to launch to show UI for this session.
*/
@@ -555,7 +550,7 @@
}
/**
- * Set {@link SessionCallback}.
+ * Set callback for the session.
*
* @param executor callback executor
* @param callback session callback.
@@ -581,7 +576,7 @@
* @throws IllegalStateException if the session with the same id is already exists for the
* package.
*/
- public abstract MediaSession2 build() throws IllegalStateException;
+ public abstract MediaSession2 build();
}
/**
@@ -599,12 +594,12 @@
}
@Override
- public MediaSession2 build() throws IllegalStateException {
+ public MediaSession2 build() {
if (mCallback == null) {
mCallback = new SessionCallback();
}
- return new MediaSession2(mContext, mPlayer, mId, mCallbackExecutor, mCallback,
- mVolumeProvider, mRatingType, mSessionActivity);
+ return new MediaSession2(mContext, mPlayer, mId, mVolumeProvider, mRatingType,
+ mSessionActivity, mCallbackExecutor, mCallback);
}
}
@@ -624,7 +619,7 @@
IMediaSession2Callback callback) {
mProvider = ApiLoader.getProvider(context)
.createMediaSession2ControllerInfoProvider(
- this, context, uid, pid, packageName, callback);
+ context, this, uid, pid, packageName, callback);
}
/**
@@ -652,11 +647,7 @@
return mProvider.isTrusted_impl();
}
- /**
- * @hide
- * @return
- */
- // TODO(jaewan): SystemApi
+ @SystemApi
public ControllerInfoProvider getProvider() {
return mProvider;
}
@@ -855,7 +846,7 @@
* Parameter for the playlist.
*/
// TODO(jaewan): add fromBundle()/toBundle()
- public static class PlaylistParam {
+ public static class PlaylistParams {
/**
* @hide
*/
@@ -915,7 +906,7 @@
private MediaMetadata2 mPlaylistMetadata;
- public PlaylistParam(@RepeatMode int repeatMode, @ShuffleMode int shuffleMode,
+ public PlaylistParams(@RepeatMode int repeatMode, @ShuffleMode int shuffleMode,
@Nullable MediaMetadata2 playlistMetadata) {
mRepeatMode = repeatMode;
mShuffleMode = shuffleMode;
@@ -949,26 +940,25 @@
* framework had to add heuristics to figure out if an app is
* @hide
*/
- MediaSession2(Context context, MediaPlayerBase player, String id, Executor callbackExecutor,
- SessionCallback callback, VolumeProvider volumeProvider, int ratingType,
- PendingIntent sessionActivity) {
+
+ MediaSession2(Context context, MediaPlayerBase player, String id, VolumeProvider volumeProvider,
+ int ratingType, PendingIntent sessionActivity, Executor callbackExecutor,
+ SessionCallback callback) {
super();
- mProvider = createProvider(context, player, id, callbackExecutor, callback,
- volumeProvider, ratingType, sessionActivity);
+ mProvider = createProvider(context, player, id, volumeProvider, ratingType, sessionActivity,
+ callbackExecutor, callback
+ );
}
MediaSession2Provider createProvider(Context context, MediaPlayerBase player, String id,
- Executor callbackExecutor, SessionCallback callback, VolumeProvider volumeProvider,
- int ratingType, PendingIntent sessionActivity) {
+ VolumeProvider volumeProvider, int ratingType, PendingIntent sessionActivity,
+ Executor callbackExecutor, SessionCallback callback) {
return ApiLoader.getProvider(context)
- .createMediaSession2(this, context, player, id, callbackExecutor,
- callback, volumeProvider, ratingType, sessionActivity);
+ .createMediaSession2(context, this, player, id, volumeProvider, ratingType,
+ sessionActivity, callbackExecutor, callback);
}
- /**
- * @hide
- */
- // TODO(jaewan): SystemApi
+ @SystemApi
public MediaSession2Provider getProvider() {
return mProvider;
}
@@ -998,10 +988,8 @@
* @param volumeProvider a volume provider
* @see #setPlayer(MediaPlayerBase)
* @see Builder#setVolumeProvider(VolumeProvider)
- * @throws IllegalArgumentException if a parameter is {@code null}.
*/
- public void setPlayer(@NonNull MediaPlayerBase player, @NonNull VolumeProvider volumeProvider)
- throws IllegalArgumentException {
+ public void setPlayer(@NonNull MediaPlayerBase player, @NonNull VolumeProvider volumeProvider) {
mProvider.setPlayer_impl(player, volumeProvider);
}
@@ -1217,7 +1205,7 @@
// To match with KEYCODE_MEDIA_SKIP_BACKWARD
}
- public void setPlaylist(@NonNull List<MediaItem2> playlist, @NonNull PlaylistParam param) {
+ public void setPlaylist(@NonNull List<MediaItem2> playlist, @NonNull PlaylistParams param) {
mProvider.setPlaylist_impl(playlist, param);
}
}
diff --git a/media/java/android/media/MediaSessionService2.java b/media/java/android/media/MediaSessionService2.java
index 19814f0..6b2de06 100644
--- a/media/java/android/media/MediaSessionService2.java
+++ b/media/java/android/media/MediaSessionService2.java
@@ -23,7 +23,6 @@
import android.app.Service;
import android.content.Intent;
import android.media.MediaSession2.ControllerInfo;
-import android.media.session.PlaybackState;
import android.media.update.ApiLoader;
import android.media.update.MediaSessionService2Provider;
import android.os.IBinder;
@@ -89,7 +88,7 @@
* rejected, the controller will unbind. If it's accepted, the controller will be available to use
* and keep binding.
* <p>
- * When playback is started for this session service, {@link #onUpdateNotification(PlaybackState)}
+ * When playback is started for this session service, {@link #onUpdateNotification(PlaybackState2)}
* is called and service would become a foreground service. It's needed to keep playback after the
* controller is destroyed. The session service becomes background service when the playback is
* stopped.
@@ -99,20 +98,8 @@
* Any app can bind to the session service with controller, but the controller can be used only if
* the session service accepted the connection request through
* {@link MediaSession2.SessionCallback#onConnect(ControllerInfo)}.
- *
* @hide
*/
-// TODO(jaewan): Unhide
-// TODO(jaewan): Can we clean up sessions in onDestroy() automatically instead?
-// What about currently running SessionCallback when the onDestroy() is called?
-// TODO(jaewan): Protect this with system|privilleged permission - Q.
-// TODO(jaewan): Add permission check for the service to know incoming connection request.
-// Follow-up questions: What about asking a XML for list of white/black packages for
-// allowing enumeration?
-// We can read the information even when the service is started,
-// so SessionManager.getXXXXService() can only return apps
-// TODO(jaewan): Will be the black/white listing persistent?
-// In other words, can we cache the rejection?
public abstract class MediaSessionService2 extends Service {
private final MediaSessionService2Provider mProvider;
@@ -213,7 +200,7 @@
}
/**
- * Returned by {@link #onUpdateNotification(PlaybackState)} for making session service
+ * Returned by {@link #onUpdateNotification(PlaybackState2)} for making session service
* foreground service to keep playback running in the background. It's highly recommended to
* show media style notification here.
*/
diff --git a/media/java/android/media/PlaybackState2.java b/media/java/android/media/PlaybackState2.java
index 46d6f45..04f211d 100644
--- a/media/java/android/media/PlaybackState2.java
+++ b/media/java/android/media/PlaybackState2.java
@@ -28,7 +28,6 @@
* the current playback position and extra.
* @hide
*/
-// TODO(jaewan): Move to updatable
public final class PlaybackState2 {
private static final String TAG = "PlaybackState2";
diff --git a/media/java/android/media/Rating2.java b/media/java/android/media/Rating2.java
index 67e5e72..93aea6f 100644
--- a/media/java/android/media/Rating2.java
+++ b/media/java/android/media/Rating2.java
@@ -32,7 +32,6 @@
* through one of the factory methods.
* @hide
*/
-// TODO(jaewan): Move this to updatable
public final class Rating2 {
private static final String TAG = "Rating2";
diff --git a/media/java/android/media/SessionToken2.java b/media/java/android/media/SessionToken2.java
index 697a5a8..0abb852 100644
--- a/media/java/android/media/SessionToken2.java
+++ b/media/java/android/media/SessionToken2.java
@@ -37,9 +37,7 @@
* It can be also obtained by {@link MediaSessionManager}.
* @hide
*/
-// TODO(jaewan): Unhide. SessionToken2?
// TODO(jaewan): Move Token to updatable!
-// TODO(jaewan): Find better name for this (SessionToken or Session2Token)
public final class SessionToken2 {
@Retention(RetentionPolicy.SOURCE)
@IntDef(value = {TYPE_SESSION, TYPE_SESSION_SERVICE, TYPE_LIBRARY_SERVICE})
@@ -210,7 +208,6 @@
* Create a {@link Bundle} from this token to share it across processes.
*
* @return Bundle
- * @hide
*/
public Bundle toBundle() {
Bundle bundle = new Bundle();
diff --git a/media/java/android/media/update/MediaBrowser2Provider.java b/media/java/android/media/update/MediaBrowser2Provider.java
index e48711d..67680c7 100644
--- a/media/java/android/media/update/MediaBrowser2Provider.java
+++ b/media/java/android/media/update/MediaBrowser2Provider.java
@@ -16,6 +16,7 @@
package android.media.update;
+import android.annotation.SystemApi;
import android.os.Bundle;
/**
diff --git a/media/java/android/media/update/MediaController2Provider.java b/media/java/android/media/update/MediaController2Provider.java
index c5f6b96..8dfb892 100644
--- a/media/java/android/media/update/MediaController2Provider.java
+++ b/media/java/android/media/update/MediaController2Provider.java
@@ -16,11 +16,12 @@
package android.media.update;
+import android.annotation.SystemApi;
import android.app.PendingIntent;
import android.media.MediaController2.PlaybackInfo;
import android.media.MediaItem2;
import android.media.MediaSession2.Command;
-import android.media.MediaSession2.PlaylistParam;
+import android.media.MediaSession2.PlaylistParams;
import android.media.PlaybackState2;
import android.media.Rating2;
import android.media.SessionToken2;
@@ -59,6 +60,6 @@
void removePlaylistItem_impl(MediaItem2 index);
void addPlaylistItem_impl(int index, MediaItem2 item);
- PlaylistParam getPlaylistParam_impl();
+ PlaylistParams getPlaylistParam_impl();
PlaybackState2 getPlaybackState_impl();
}
diff --git a/media/java/android/media/update/MediaLibraryService2Provider.java b/media/java/android/media/update/MediaLibraryService2Provider.java
index dac5784..a568839 100644
--- a/media/java/android/media/update/MediaLibraryService2Provider.java
+++ b/media/java/android/media/update/MediaLibraryService2Provider.java
@@ -16,8 +16,11 @@
package android.media.update;
+import android.annotation.SystemApi;
import android.media.MediaSession2.ControllerInfo;
-import android.os.Bundle; /**
+import android.os.Bundle;
+
+/**
* @hide
*/
public interface MediaLibraryService2Provider extends MediaSessionService2Provider {
diff --git a/media/java/android/media/update/MediaSession2Provider.java b/media/java/android/media/update/MediaSession2Provider.java
index 2a68ad1..d32b741 100644
--- a/media/java/android/media/update/MediaSession2Provider.java
+++ b/media/java/android/media/update/MediaSession2Provider.java
@@ -16,14 +16,15 @@
package android.media.update;
+import android.annotation.SystemApi;
import android.media.AudioAttributes;
import android.media.MediaItem2;
import android.media.MediaPlayerBase;
-import android.media.MediaSession2;
import android.media.MediaSession2.Command;
import android.media.MediaSession2.CommandButton;
import android.media.MediaSession2.CommandGroup;
import android.media.MediaSession2.ControllerInfo;
+import android.media.MediaSession2.PlaylistParams;
import android.media.SessionToken2;
import android.media.VolumeProvider;
import android.os.Bundle;
@@ -50,11 +51,8 @@
void sendCustomCommand_impl(ControllerInfo controller, Command command, Bundle args,
ResultReceiver receiver);
void sendCustomCommand_impl(Command command, Bundle args);
- void setPlaylist_impl(List<MediaItem2> playlist, MediaSession2.PlaylistParam param);
+ void setPlaylist_impl(List<MediaItem2> playlist, PlaylistParams param);
- /**
- * @hide
- */
interface ControllerInfoProvider {
String getPackageName_impl();
int getUid_impl();
diff --git a/media/java/android/media/update/MediaSessionService2Provider.java b/media/java/android/media/update/MediaSessionService2Provider.java
index a6b462b..9455da7 100644
--- a/media/java/android/media/update/MediaSessionService2Provider.java
+++ b/media/java/android/media/update/MediaSessionService2Provider.java
@@ -16,6 +16,7 @@
package android.media.update;
+import android.annotation.SystemApi;
import android.content.Intent;
import android.media.MediaSession2;
import android.media.MediaSessionService2.MediaNotification;
diff --git a/media/java/android/media/update/StaticProvider.java b/media/java/android/media/update/StaticProvider.java
index 7c222c3..3cd1a99 100644
--- a/media/java/android/media/update/StaticProvider.java
+++ b/media/java/android/media/update/StaticProvider.java
@@ -17,9 +17,9 @@
package android.media.update;
import android.annotation.Nullable;
+import android.annotation.SystemApi;
import android.app.PendingIntent;
import android.content.Context;
-import android.media.IMediaSession2Callback;
import android.media.MediaBrowser2;
import android.media.MediaBrowser2.BrowserCallback;
import android.media.MediaController2;
@@ -35,6 +35,7 @@
import android.media.VolumeProvider;
import android.media.update.MediaLibraryService2Provider.MediaLibrarySessionProvider;
import android.media.update.MediaSession2Provider.ControllerInfoProvider;
+import android.os.IInterface;
import android.util.AttributeSet;
import android.widget.MediaControlView2;
import android.widget.VideoView2;
@@ -46,10 +47,8 @@
*
* This interface provides access to constructors and static methods that are otherwise not directly
* accessible via an implementation object.
- *
* @hide
*/
-// TODO @SystemApi
public interface StaticProvider {
MediaControlView2Provider createMediaControlView2(
MediaControlView2 instance, ViewProvider superProvider);
@@ -57,25 +56,20 @@
VideoView2 instance, ViewProvider superProvider,
@Nullable AttributeSet attrs, int defStyleAttr, int defStyleRes);
- MediaSession2Provider createMediaSession2(MediaSession2 mediaSession2, Context context,
- MediaPlayerBase player, String id, Executor callbackExecutor, SessionCallback callback,
- VolumeProvider volumeProvider, int ratingType,
- PendingIntent sessionActivity);
- ControllerInfoProvider createMediaSession2ControllerInfoProvider(
- MediaSession2.ControllerInfo instance, Context context, int uid, int pid,
- String packageName, IMediaSession2Callback callback);
- MediaController2Provider createMediaController2(
- MediaController2 instance, Context context, SessionToken2 token,
- ControllerCallback callback, Executor executor);
- MediaBrowser2Provider createMediaBrowser2(
- MediaBrowser2 instance, Context context, SessionToken2 token,
- BrowserCallback callback, Executor executor);
- MediaSessionService2Provider createMediaSessionService2(
- MediaSessionService2 instance);
- MediaSessionService2Provider createMediaLibraryService2(
- MediaLibraryService2 instance);
- MediaLibrarySessionProvider createMediaLibraryService2MediaLibrarySession(
- MediaLibrarySession instance, Context context, MediaPlayerBase player, String id,
- Executor callbackExecutor, MediaLibrarySessionCallback callback,
- VolumeProvider volumeProvider, int ratingType, PendingIntent sessionActivity);
+ MediaSession2Provider createMediaSession2(Context context, MediaSession2 instance,
+ MediaPlayerBase player, String id, VolumeProvider volumeProvider, int ratingType,
+ PendingIntent sessionActivity, Executor executor, SessionCallback callback);
+ ControllerInfoProvider createMediaSession2ControllerInfoProvider(Context context,
+ MediaSession2.ControllerInfo instance, int uid, int pid,
+ String packageName, IInterface callback);
+ MediaController2Provider createMediaController2(Context context, MediaController2 instance,
+ SessionToken2 token, Executor executor, ControllerCallback callback);
+ MediaBrowser2Provider createMediaBrowser2(Context context, MediaBrowser2 instance,
+ SessionToken2 token, Executor executor, BrowserCallback callback);
+ MediaSessionService2Provider createMediaSessionService2(MediaSessionService2 instance);
+ MediaSessionService2Provider createMediaLibraryService2(MediaLibraryService2 instance);
+ MediaLibrarySessionProvider createMediaLibraryService2MediaLibrarySession(Context context,
+ MediaLibrarySession instance, MediaPlayerBase player, String id,
+ VolumeProvider volumeProvider, int ratingType, PendingIntent sessionActivity,
+ Executor executor, MediaLibrarySessionCallback callback);
}
diff --git a/media/java/android/media/update/TransportControlProvider.java b/media/java/android/media/update/TransportControlProvider.java
index 5217a9d..0c87063e 100644
--- a/media/java/android/media/update/TransportControlProvider.java
+++ b/media/java/android/media/update/TransportControlProvider.java
@@ -16,14 +16,9 @@
package android.media.update;
-import android.media.MediaPlayerBase;
-import android.media.session.PlaybackState;
-import android.os.Handler;
-
/**
* @hide
*/
-// TODO(jaewan): SystemApi
public interface TransportControlProvider {
void play_impl();
void pause_impl();
diff --git a/media/java/android/media/update/VideoView2Provider.java b/media/java/android/media/update/VideoView2Provider.java
index 416ea98..5c05ce4 100644
--- a/media/java/android/media/update/VideoView2Provider.java
+++ b/media/java/android/media/update/VideoView2Provider.java
@@ -18,6 +18,7 @@
import android.media.AudioAttributes;
import android.media.MediaPlayerBase;
+import android.media.session.MediaController;
import android.net.Uri;
import android.widget.MediaControlView2;
import android.widget.VideoView2;
@@ -41,20 +42,14 @@
// TODO @SystemApi
public interface VideoView2Provider extends ViewProvider {
void setMediaControlView2_impl(MediaControlView2 mediaControlView);
+ MediaController getMediaController_impl();
MediaControlView2 getMediaControlView2_impl();
- void start_impl();
- void pause_impl();
- int getDuration_impl();
- int getCurrentPosition_impl();
- void seekTo_impl(int msec);
- boolean isPlaying_impl();
- int getBufferPercentage_impl();
int getAudioSessionId_impl();
void showSubtitle_impl();
void hideSubtitle_impl();
void setFullScreen_impl(boolean fullScreen);
+ // TODO: remove setSpeed_impl once MediaController2 is ready.
void setSpeed_impl(float speed);
- float getSpeed_impl();
void setAudioFocusRequest_impl(int focusGain);
void setAudioAttributes_impl(AudioAttributes attributes);
void setRouteAttributes_impl(List<String> routeCategories, MediaPlayerBase player);
@@ -63,7 +58,6 @@
void setVideoURI_impl(Uri uri, Map<String, String> headers);
void setViewType_impl(int viewType);
int getViewType_impl();
- void stopPlayback_impl();
void setOnPreparedListener_impl(VideoView2.OnPreparedListener l);
void setOnCompletionListener_impl(VideoView2.OnCompletionListener l);
void setOnErrorListener_impl(VideoView2.OnErrorListener l);
diff --git a/media/jni/Android.bp b/media/jni/Android.bp
index ee775db..051c802 100644
--- a/media/jni/Android.bp
+++ b/media/jni/Android.bp
@@ -12,7 +12,6 @@
"android_media_MediaDrm.cpp",
"android_media_MediaExtractor.cpp",
"android_media_MediaHTTPConnection.cpp",
- "android_media_MediaMetricsJNI.cpp",
"android_media_MediaMetadataRetriever.cpp",
"android_media_MediaMuxer.cpp",
"android_media_MediaPlayer.cpp",
@@ -93,7 +92,6 @@
"android_media_MediaCrypto.cpp",
"android_media_Media2DataSource.cpp",
"android_media_MediaDrm.cpp",
- "android_media_MediaMetricsJNI.cpp",
"android_media_MediaPlayer2.cpp",
"android_media_SyncParams.cpp",
],
diff --git a/media/jni/android_media_MediaExtractor.cpp b/media/jni/android_media_MediaExtractor.cpp
index 5c90d00..a855526 100644
--- a/media/jni/android_media_MediaExtractor.cpp
+++ b/media/jni/android_media_MediaExtractor.cpp
@@ -244,6 +244,10 @@
return mImpl->getSampleTime(sampleTimeUs);
}
+status_t JMediaExtractor::getSampleSize(size_t *sampleSize) {
+ return mImpl->getSampleSize(sampleSize);
+}
+
status_t JMediaExtractor::getSampleFlags(uint32_t *sampleFlags) {
*sampleFlags = 0;
@@ -505,6 +509,28 @@
return (jlong) sampleTimeUs;
}
+static jlong android_media_MediaExtractor_getSampleSize(
+ JNIEnv *env, jobject thiz) {
+ sp<JMediaExtractor> extractor = getMediaExtractor(env, thiz);
+
+ if (extractor == NULL) {
+ jniThrowException(env, "java/lang/IllegalStateException", NULL);
+ return -1ll;
+ }
+
+ size_t sampleSize;
+ status_t err = extractor->getSampleSize(&sampleSize);
+
+ if (err == ERROR_END_OF_STREAM) {
+ return -1ll;
+ } else if (err != OK) {
+ jniThrowException(env, "java/lang/IllegalArgumentException", NULL);
+ return -1ll;
+ }
+
+ return (jlong) sampleSize;
+}
+
static jint android_media_MediaExtractor_getSampleFlags(
JNIEnv *env, jobject thiz) {
sp<JMediaExtractor> extractor = getMediaExtractor(env, thiz);
@@ -884,6 +910,9 @@
{ "getSampleTime", "()J",
(void *)android_media_MediaExtractor_getSampleTime },
+ { "getSampleSize", "()J",
+ (void *)android_media_MediaExtractor_getSampleSize },
+
{ "getSampleFlags", "()I",
(void *)android_media_MediaExtractor_getSampleFlags },
diff --git a/media/jni/android_media_MediaExtractor.h b/media/jni/android_media_MediaExtractor.h
index a4638ac..aaa8421 100644
--- a/media/jni/android_media_MediaExtractor.h
+++ b/media/jni/android_media_MediaExtractor.h
@@ -60,6 +60,7 @@
status_t readSampleData(jobject byteBuf, size_t offset, size_t *sampleSize);
status_t getSampleTrackIndex(size_t *trackIndex);
status_t getSampleTime(int64_t *sampleTimeUs);
+ status_t getSampleSize(size_t *sampleSize);
status_t getSampleFlags(uint32_t *sampleFlags);
status_t getSampleMeta(sp<MetaData> *sampleMeta);
status_t getMetrics(Parcel *reply) const;
diff --git a/packages/SettingsLib/src/com/android/settingslib/Utils.java b/packages/SettingsLib/src/com/android/settingslib/Utils.java
index d001e66..1f67dfb 100644
--- a/packages/SettingsLib/src/com/android/settingslib/Utils.java
+++ b/packages/SettingsLib/src/com/android/settingslib/Utils.java
@@ -44,7 +44,11 @@
com.android.internal.R.drawable.ic_wifi_signal_4
};
- public static void updateLocationEnabled(Context context, boolean enabled, int userId) {
+ public static void updateLocationEnabled(Context context, boolean enabled, int userId,
+ int source) {
+ Settings.Secure.putIntForUser(
+ context.getContentResolver(), Settings.Secure.LOCATION_CHANGER, source,
+ userId);
Intent intent = new Intent(LocationManager.MODE_CHANGING_ACTION);
final int oldMode = Settings.Secure.getIntForUser(context.getContentResolver(),
@@ -62,7 +66,11 @@
wrapper.setLocationEnabledForUser(enabled, UserHandle.of(userId));
}
- public static boolean updateLocationMode(Context context, int oldMode, int newMode, int userId) {
+ public static boolean updateLocationMode(Context context, int oldMode, int newMode, int userId,
+ int source) {
+ Settings.Secure.putIntForUser(
+ context.getContentResolver(), Settings.Secure.LOCATION_CHANGER, source,
+ userId);
Intent intent = new Intent(LocationManager.MODE_CHANGING_ACTION);
intent.putExtra(CURRENT_MODE_KEY, oldMode);
intent.putExtra(NEW_MODE_KEY, newMode);
diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/UtilsTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/UtilsTest.java
index 327c1c8..5459fb7 100644
--- a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/UtilsTest.java
+++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/UtilsTest.java
@@ -84,23 +84,31 @@
mContext,
Secure.LOCATION_MODE_OFF,
Secure.LOCATION_MODE_HIGH_ACCURACY,
- currentUserId);
+ currentUserId,
+ Settings.Secure.LOCATION_CHANGER_QUICK_SETTINGS);
verify(mContext).sendBroadcastAsUser(
argThat(actionMatches(LocationManager.MODE_CHANGING_ACTION)),
ArgumentMatchers.eq(UserHandle.of(currentUserId)),
ArgumentMatchers.eq(WRITE_SECURE_SETTINGS));
+ assertThat(Settings.Secure.getInt(mContext.getContentResolver(),
+ Settings.Secure.LOCATION_CHANGER, Settings.Secure.LOCATION_CHANGER_UNKNOWN))
+ .isEqualTo(Settings.Secure.LOCATION_CHANGER_QUICK_SETTINGS);
}
@Test
public void testUpdateLocationEnabled_sendBroadcast() {
int currentUserId = ActivityManager.getCurrentUser();
- Utils.updateLocationEnabled(mContext, true, currentUserId);
+ Utils.updateLocationEnabled(mContext, true, currentUserId,
+ Settings.Secure.LOCATION_CHANGER_QUICK_SETTINGS);
verify(mContext).sendBroadcastAsUser(
argThat(actionMatches(LocationManager.MODE_CHANGING_ACTION)),
ArgumentMatchers.eq(UserHandle.of(currentUserId)),
ArgumentMatchers.eq(WRITE_SECURE_SETTINGS));
+ assertThat(Settings.Secure.getInt(mContext.getContentResolver(),
+ Settings.Secure.LOCATION_CHANGER, Settings.Secure.LOCATION_CHANGER_UNKNOWN))
+ .isEqualTo(Settings.Secure.LOCATION_CHANGER_QUICK_SETTINGS);
}
@Test
diff --git a/packages/SystemUI/plugin/src/com/android/systemui/plugins/qs/QS.java b/packages/SystemUI/plugin/src/com/android/systemui/plugins/qs/QS.java
index a648345e..30d1352 100644
--- a/packages/SystemUI/plugin/src/com/android/systemui/plugins/qs/QS.java
+++ b/packages/SystemUI/plugin/src/com/android/systemui/plugins/qs/QS.java
@@ -14,6 +14,7 @@
package com.android.systemui.plugins.qs;
+import android.view.MotionEvent;
import android.view.View;
import android.view.View.OnClickListener;
import android.view.ViewGroup;
@@ -65,6 +66,18 @@
default void setHasNotifications(boolean hasNotifications) {
}
+ /**
+ * We need this to handle nested scrolling for QS..
+ * Normally we would do this with requestDisallowInterceptTouchEvent, but when both the
+ * scroll containers are using the same touch slop, they try to start scrolling at the
+ * same time and NotificationPanelView wins, this lets QS win.
+ *
+ * TODO: Do this using NestedScroll capabilities.
+ */
+ default boolean onInterceptTouchEvent(MotionEvent event) {
+ return isCustomizing();
+ }
+
@ProvidesInterface(version = HeightListener.VERSION)
interface HeightListener {
int VERSION = 1;
diff --git a/packages/SystemUI/res/values/dimens.xml b/packages/SystemUI/res/values/dimens.xml
index 7ee9eda..d58c725 100644
--- a/packages/SystemUI/res/values/dimens.xml
+++ b/packages/SystemUI/res/values/dimens.xml
@@ -336,6 +336,8 @@
<dimen name="qs_footer_padding_end">24dp</dimen>
<dimen name="qs_footer_icon_size">16dp</dimen>
+ <dimen name="qs_notif_collapsed_space">64dp</dimen>
+
<!-- Desired qs icon overlay size. -->
<dimen name="qs_detail_icon_overlay_size">24dp</dimen>
diff --git a/packages/SystemUI/res/values/donottranslate.xml b/packages/SystemUI/res/values/donottranslate.xml
index 351a1fd..38f469e 100644
--- a/packages/SystemUI/res/values/donottranslate.xml
+++ b/packages/SystemUI/res/values/donottranslate.xml
@@ -20,4 +20,6 @@
<!-- Date format for display: should match the lockscreen in /policy. -->
<string name="system_ui_date_pattern">@*android:string/system_ui_date_pattern</string>
+ <!-- Date format for the always on display. -->
+ <item type="string" name="system_ui_aod_date_pattern">eeeMMMd</item>
</resources>
diff --git a/packages/SystemUI/res/values/strings.xml b/packages/SystemUI/res/values/strings.xml
index 209d444..6d61a0c 100644
--- a/packages/SystemUI/res/values/strings.xml
+++ b/packages/SystemUI/res/values/strings.xml
@@ -1506,6 +1506,10 @@
<string name="notification_channel_disabled">You won\'t see these notifications anymore</string>
<!-- Notification Inline controls: continue receiving notifications prompt, channel level -->
+ <string name="inline_blocking_helper">You usually dismiss these notifications.
+ \nKeep showing them?</string>
+
+ <!-- Notification Inline controls: continue receiving notifications prompt, channel level -->
<string name="inline_keep_showing">Keep showing these notifications?</string>
<!-- Notification inline controls: block notifications button -->
diff --git a/packages/SystemUI/res/values/styles.xml b/packages/SystemUI/res/values/styles.xml
index bcce6d1..2497d20 100644
--- a/packages/SystemUI/res/values/styles.xml
+++ b/packages/SystemUI/res/values/styles.xml
@@ -306,6 +306,7 @@
<item name="darkIconTheme">@style/DualToneDarkTheme</item>
<item name="wallpaperTextColor">@*android:color/primary_text_material_dark</item>
<item name="wallpaperTextColorSecondary">@*android:color/secondary_text_material_dark</item>
+ <item name="android:colorError">@*android:color/error_color_material_dark</item>
<item name="android:colorControlHighlight">@*android:color/primary_text_material_dark</item>
<item name="*android:lockPatternStyle">@style/LockPatternStyle</item>
<item name="passwordStyle">@style/PasswordTheme</item>
@@ -317,6 +318,7 @@
<style name="Theme.SystemUI.Light" parent="@*android:style/Theme.DeviceDefault.QuickSettings">
<item name="wallpaperTextColor">@*android:color/primary_text_material_light</item>
<item name="wallpaperTextColorSecondary">@*android:color/secondary_text_material_light</item>
+ <item name="android:colorError">@*android:color/error_color_material_light</item>
<item name="android:colorControlHighlight">@*android:color/primary_text_material_light</item>
<item name="passwordStyle">@style/PasswordTheme.Light</item>
</style>
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardSliceView.java b/packages/SystemUI/src/com/android/keyguard/KeyguardSliceView.java
index 9ff6815..cb732c4 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardSliceView.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardSliceView.java
@@ -51,6 +51,8 @@
import androidx.app.slice.Slice;
import androidx.app.slice.SliceItem;
import androidx.app.slice.core.SliceQuery;
+import androidx.app.slice.widget.ListContent;
+import androidx.app.slice.widget.RowContent;
import androidx.app.slice.widget.SliceLiveData;
/**
@@ -115,25 +117,17 @@
private void showSlice(Slice slice) {
- // Main area
- SliceItem mainItem = SliceQuery.find(slice, android.app.slice.SliceItem.FORMAT_SLICE,
- null /* hints */, new String[]{android.app.slice.Slice.HINT_LIST_ITEM});
- mHasHeader = mainItem != null;
-
- List<SliceItem> subItems = SliceQuery.findAll(slice,
- android.app.slice.SliceItem.FORMAT_SLICE,
- new String[]{android.app.slice.Slice.HINT_LIST_ITEM},
- null /* nonHints */);
-
+ ListContent lc = new ListContent(slice);
+ mHasHeader = lc.hasHeader();
+ List<SliceItem> subItems = lc.getRowItems();
if (!mHasHeader) {
mTitle.setVisibility(GONE);
} else {
mTitle.setVisibility(VISIBLE);
- SliceItem mainTitle = SliceQuery.find(mainItem.getSlice(),
- android.app.slice.SliceItem.FORMAT_TEXT,
- new String[]{android.app.slice.Slice.HINT_TITLE},
- null /* nonHints */);
- CharSequence title = mainTitle.getText();
+ // If there's a header it'll be the first subitem
+ RowContent header = new RowContent(subItems.get(0), true /* showStartItem */);
+ SliceItem mainTitle = header.getTitleItem();
+ CharSequence title = mainTitle != null ? mainTitle.getText() : null;
mTitle.setText(title);
// Check if we're already ellipsizing the text.
@@ -152,9 +146,10 @@
mClickActions.clear();
final int subItemsCount = subItems.size();
final int blendedColor = getTextColor();
-
- for (int i = 0; i < subItemsCount; i++) {
+ final int startIndex = mHasHeader ? 1 : 0; // First item is header; skip it
+ for (int i = startIndex; i < subItemsCount; i++) {
SliceItem item = subItems.get(i);
+ RowContent rc = new RowContent(item, true /* showStartItem */);
final Uri itemTag = item.getSlice().getUri();
// Try to reuse the view if already exists in the layout
KeyguardSliceButton button = mRow.findViewWithTag(itemTag);
@@ -168,20 +163,13 @@
button.setHasDivider(i < subItemsCount - 1);
mRow.addView(button, i);
- PendingIntent pendingIntent;
- try {
- pendingIntent = item.getAction();
- } catch (RuntimeException e) {
- Log.w(TAG, "Cannot retrieve action from keyguard slice", e);
- pendingIntent = null;
+ PendingIntent pendingIntent = null;
+ if (rc.getContentIntent() != null) {
+ pendingIntent = rc.getContentIntent().getAction();
}
mClickActions.put(button, pendingIntent);
- SliceItem title = SliceQuery.find(item.getSlice(),
- android.app.slice.SliceItem.FORMAT_TEXT,
- new String[]{android.app.slice.Slice.HINT_TITLE},
- null /* nonHints */);
- button.setText(title.getText());
+ button.setText(rc.getTitleItem().getText());
Drawable iconDrawable = null;
SliceItem icon = SliceQuery.find(item.getSlice(),
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardStatusView.java b/packages/SystemUI/src/com/android/keyguard/KeyguardStatusView.java
index 2b656c2..e440731 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardStatusView.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardStatusView.java
@@ -330,7 +330,7 @@
public void setPulsing(boolean pulsing) {
mPulsing = pulsing;
- mKeyguardSlice.setVisibility(pulsing ? GONE : VISIBLE);
+ mKeyguardSlice.setVisibility(pulsing ? INVISIBLE : VISIBLE);
onSliceContentChanged(mKeyguardSlice.hasHeader());
updateDozeVisibleViews();
}
diff --git a/packages/SystemUI/src/com/android/systemui/SystemUIApplication.java b/packages/SystemUI/src/com/android/systemui/SystemUIApplication.java
index 3538327..2c0e95b 100644
--- a/packages/SystemUI/src/com/android/systemui/SystemUIApplication.java
+++ b/packages/SystemUI/src/com/android/systemui/SystemUIApplication.java
@@ -61,7 +61,7 @@
*/
public class SystemUIApplication extends Application implements SysUiServiceProvider {
- private static final String TAG = "SystemUIService";
+ public static final String TAG = "SystemUIService";
private static final boolean DEBUG = false;
/**
diff --git a/packages/SystemUI/src/com/android/systemui/SystemUIService.java b/packages/SystemUI/src/com/android/systemui/SystemUIService.java
index 11e0f28..ddf0bd0 100644
--- a/packages/SystemUI/src/com/android/systemui/SystemUIService.java
+++ b/packages/SystemUI/src/com/android/systemui/SystemUIService.java
@@ -20,11 +20,15 @@
import android.content.Intent;
import android.os.Build;
import android.os.IBinder;
+import android.os.Process;
import android.os.SystemProperties;
+import android.util.Slog;
import java.io.FileDescriptor;
import java.io.PrintWriter;
+import com.android.internal.os.BinderInternal;
+
public class SystemUIService extends Service {
@Override
@@ -36,6 +40,21 @@
if (Build.IS_DEBUGGABLE && SystemProperties.getBoolean("debug.crash_sysui", false)) {
throw new RuntimeException();
}
+
+ if (Build.IS_DEBUGGABLE) {
+ // b/71353150 - looking for leaked binder proxies
+ BinderInternal.nSetBinderProxyCountEnabled(true);
+ BinderInternal.nSetBinderProxyCountWatermarks(1000,900);
+ BinderInternal.setBinderProxyCountCallback(
+ new BinderInternal.BinderProxyLimitListener() {
+ @Override
+ public void onLimitReached(int uid) {
+ Slog.w(SystemUIApplication.TAG,
+ "uid " + uid + " sent too many Binder proxies to uid "
+ + Process.myUid());
+ }
+ }, Dependency.get(Dependency.MAIN_HANDLER));
+ }
}
@Override
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardSliceProvider.java b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardSliceProvider.java
index e49e80d..c7d276c 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardSliceProvider.java
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardSliceProvider.java
@@ -118,7 +118,7 @@
public boolean onCreateSliceProvider() {
mNextAlarmController = new NextAlarmControllerImpl(getContext());
mNextAlarmController.addCallback(this);
- mDatePattern = getContext().getString(R.string.system_ui_date_pattern);
+ mDatePattern = getContext().getString(R.string.system_ui_aod_date_pattern);
registerClockUpdate(false /* everyMinute */);
updateClock();
return true;
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSAnimator.java b/packages/SystemUI/src/com/android/systemui/qs/QSAnimator.java
index 8f18800..95185c0 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QSAnimator.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QSAnimator.java
@@ -244,10 +244,8 @@
mFirstPageDelayedAnimator = new TouchAnimator.Builder()
.setStartDelay(EXPANDED_TILE_DELAY)
.addFloat(tileLayout, "alpha", 0, 1)
- .addFloat(mQsPanel.getPageIndicator(), "alpha", 0, 1)
.addFloat(mQsPanel.getDivider(), "alpha", 0, 1)
.addFloat(mQsPanel.getFooter().getView(), "alpha", 0, 1).build();
- mAllViews.add(mQsPanel.getPageIndicator());
mAllViews.add(mQsPanel.getDivider());
mAllViews.add(mQsPanel.getFooter().getView());
float px = 0;
@@ -265,7 +263,6 @@
}
mNonfirstPageAnimator = new TouchAnimator.Builder()
.addFloat(mQuickQsPanel, "alpha", 1, 0)
- .addFloat(mQsPanel.getPageIndicator(), "alpha", 0, 1)
.addFloat(mQsPanel.getDivider(), "alpha", 0, 1)
.setListener(mNonFirstPageListener)
.setEndDelay(.5f)
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSContainerImpl.java b/packages/SystemUI/src/com/android/systemui/qs/QSContainerImpl.java
index 7320b86..6b0d592 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QSContainerImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QSContainerImpl.java
@@ -17,11 +17,11 @@
package com.android.systemui.qs;
import android.content.Context;
+import android.content.res.Configuration;
import android.graphics.Canvas;
import android.graphics.Path;
import android.graphics.Point;
import android.util.AttributeSet;
-import android.util.Log;
import android.view.View;
import android.widget.FrameLayout;
@@ -80,11 +80,22 @@
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
+ getDisplay().getRealSize(mSizePoint);
+
// Since we control our own bottom, be whatever size we want.
// Otherwise the QSPanel ends up with 0 height when the window is only the
// size of the status bar.
- mQSPanel.measure(widthMeasureSpec, MeasureSpec.makeMeasureSpec(
- MeasureSpec.getSize(heightMeasureSpec), MeasureSpec.UNSPECIFIED));
+ Configuration config = getResources().getConfiguration();
+ boolean navBelow = config.smallestScreenWidthDp >= 600
+ || config.orientation != Configuration.ORIENTATION_LANDSCAPE;
+ MarginLayoutParams params = (MarginLayoutParams) mQSPanel.getLayoutParams();
+ int maxQs = mSizePoint.y - params.topMargin - params.bottomMargin - getPaddingBottom()
+ - getResources().getDimensionPixelSize(R.dimen.qs_notif_collapsed_space);
+ if (navBelow) {
+ maxQs -= getResources().getDimensionPixelSize(R.dimen.navigation_bar_height);
+ }
+ mQSPanel.measure(widthMeasureSpec, MeasureSpec.makeMeasureSpec(maxQs, MeasureSpec.AT_MOST));
+
int width = mQSPanel.getMeasuredWidth();
LayoutParams layoutParams = (LayoutParams) mQSPanel.getLayoutParams();
int height = layoutParams.topMargin + layoutParams.bottomMargin
@@ -94,7 +105,6 @@
// QSCustomizer will always be the height of the screen, but do this after
// other measuring to avoid changing the height of the QS.
- getDisplay().getRealSize(mSizePoint);
mQSCustomizer.measure(widthMeasureSpec,
MeasureSpec.makeMeasureSpec(mSizePoint.y, MeasureSpec.EXACTLY));
}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSFragment.java b/packages/SystemUI/src/com/android/systemui/qs/QSFragment.java
index cdf0c0f..29a8f16 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QSFragment.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QSFragment.java
@@ -25,6 +25,7 @@
import android.util.Log;
import android.view.ContextThemeWrapper;
import android.view.LayoutInflater;
+import android.view.MotionEvent;
import android.view.View;
import android.view.View.OnClickListener;
import android.view.ViewGroup;
@@ -207,6 +208,11 @@
}
@Override
+ public boolean onInterceptTouchEvent(MotionEvent event) {
+ return isCustomizing() || mQSPanel.onInterceptTouchEvent(event);
+ }
+
+ @Override
public void setHeaderClickable(boolean clickable) {
if (DEBUG) Log.d(TAG, "setHeaderClickable " + clickable);
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSPanel.java b/packages/SystemUI/src/com/android/systemui/qs/QSPanel.java
index 310e12e..00b6c1e 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QSPanel.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QSPanel.java
@@ -28,8 +28,8 @@
import android.service.quicksettings.Tile;
import android.util.AttributeSet;
import android.view.LayoutInflater;
+import android.view.MotionEvent;
import android.view.View;
-import android.widget.ImageView;
import android.widget.LinearLayout;
import com.android.internal.logging.MetricsLogger;
@@ -62,11 +62,8 @@
protected final ArrayList<TileRecord> mRecords = new ArrayList<TileRecord>();
protected final View mBrightnessView;
private final H mHandler = new H();
- private final View mPageIndicator;
private final MetricsLogger mMetricsLogger = Dependency.get(MetricsLogger.class);
- private int mPanelPaddingBottom;
- private int mBrightnessPaddingTop;
protected boolean mExpanded;
protected boolean mListening;
@@ -77,6 +74,7 @@
protected QSSecurityFooter mFooter;
private boolean mGridContentVisible = true;
+ private QSScrollLayout mScrollLayout;
protected QSTileLayout mTileLayout;
private QSCustomizer mCustomizePanel;
@@ -95,18 +93,12 @@
setOrientation(VERTICAL);
- mBrightnessView = LayoutInflater.from(context).inflate(
- R.layout.quick_settings_brightness_dialog, this, false);
- addView(mBrightnessView);
-
- setupTileLayout();
-
- mPageIndicator = LayoutInflater.from(context).inflate(
- R.layout.qs_page_indicator, this, false);
- addView(mPageIndicator);
- if (mTileLayout instanceof PagedTileLayout) {
- ((PagedTileLayout) mTileLayout).setPageIndicator((PageIndicator) mPageIndicator);
- }
+ mBrightnessView = LayoutInflater.from(mContext).inflate(
+ R.layout.quick_settings_brightness_dialog, this, false);
+ mTileLayout = new TileLayout(mContext);
+ mTileLayout.setListening(mListening);
+ mScrollLayout = new QSScrollLayout(mContext, mBrightnessView, (View) mTileLayout);
+ addView(mScrollLayout);
addDivider();
@@ -131,17 +123,6 @@
return mDivider;
}
- public View getPageIndicator() {
- return mPageIndicator;
- }
-
- protected void setupTileLayout() {
- mTileLayout = (QSTileLayout) LayoutInflater.from(mContext).inflate(
- R.layout.qs_paged_tile_layout, this, false);
- mTileLayout.setListening(mListening);
- addView((View) mTileLayout);
- }
-
public boolean isShowingCustomize() {
return mCustomizePanel != null && mCustomizePanel.isCustomizing();
}
@@ -241,9 +222,13 @@
public void updateResources() {
final Resources res = mContext.getResources();
- mPanelPaddingBottom = res.getDimensionPixelSize(R.dimen.qs_panel_padding_bottom);
- mBrightnessPaddingTop = res.getDimensionPixelSize(R.dimen.qs_brightness_padding_top);
- setPadding(0, mBrightnessPaddingTop, 0, mPanelPaddingBottom);
+ mBrightnessView.setPadding(
+ mBrightnessView.getPaddingLeft(),
+ res.getDimensionPixelSize(R.dimen.qs_brightness_padding_top),
+ mBrightnessView.getPaddingRight(),
+ mBrightnessView.getPaddingBottom());
+ setPadding(
+ 0, 0, 0, res.getDimensionPixelSize(R.dimen.qs_panel_padding_bottom));
for (TileRecord r : mRecords) {
r.tile.clearState();
}
@@ -282,8 +267,11 @@
public void setExpanded(boolean expanded) {
if (mExpanded == expanded) return;
mExpanded = expanded;
- if (!mExpanded && mTileLayout instanceof PagedTileLayout) {
- ((PagedTileLayout) mTileLayout).setCurrentItem(0, false);
+ if (!mExpanded) {
+ if (mTileLayout instanceof PagedTileLayout) {
+ ((PagedTileLayout) mTileLayout).setCurrentItem(0, false);
+ }
+ mScrollLayout.setScrollY(0);
}
mMetricsLogger.visibility(MetricsEvent.QS_PANEL, mExpanded);
if (!mExpanded) {
@@ -565,6 +553,11 @@
mFooter.showDeviceMonitoringDialog();
}
+ @Override
+ public boolean onInterceptTouchEvent(MotionEvent event) {
+ return mExpanded && mScrollLayout.shouldIntercept(event);
+ }
+
private class H extends Handler {
private static final int SHOW_DETAIL = 1;
private static final int SET_TILE_VISIBILITY = 2;
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSScrollLayout.java b/packages/SystemUI/src/com/android/systemui/qs/QSScrollLayout.java
new file mode 100644
index 0000000..9a74787
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/qs/QSScrollLayout.java
@@ -0,0 +1,83 @@
+/*
+ * Copyright (C) 2018 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.qs;
+
+import android.content.Context;
+import android.graphics.Rect;
+import android.support.v4.widget.NestedScrollView;
+import android.view.MotionEvent;
+import android.view.View;
+import android.view.ViewConfiguration;
+import android.view.ViewParent;
+import android.widget.LinearLayout;
+
+/**
+ * Quick setting scroll view containing the brightness slider and the QS tiles.
+ *
+ * <p>Call {@link #shouldIntercept(MotionEvent)} from parent views'
+ * {@link #onInterceptTouchEvent(MotionEvent)} method to determine whether this view should
+ * consume the touch event.
+ */
+public class QSScrollLayout extends NestedScrollView {
+ private final int mTouchSlop;
+ private int mLastMotionY;
+ private Rect mHitRect = new Rect();
+
+ public QSScrollLayout(Context context, View... children) {
+ super(context);
+ mTouchSlop = ViewConfiguration.get(getContext()).getScaledTouchSlop();
+ LinearLayout linearLayout = new LinearLayout(mContext);
+ linearLayout.setLayoutParams(new LinearLayout.LayoutParams(
+ LinearLayout.LayoutParams.MATCH_PARENT,
+ LinearLayout.LayoutParams.WRAP_CONTENT));
+ linearLayout.setOrientation(LinearLayout.VERTICAL);
+ for (View view : children) {
+ linearLayout.addView(view);
+ }
+ addView(linearLayout);
+ }
+
+ public boolean shouldIntercept(MotionEvent ev) {
+ getHitRect(mHitRect);
+ if (!mHitRect.contains((int) ev.getX(), (int) ev.getY())) {
+ // Do not intercept touches that are not within this view's bounds.
+ return false;
+ }
+ if (ev.getActionMasked() == MotionEvent.ACTION_DOWN) {
+ mLastMotionY = (int) ev.getY();
+ } else if (ev.getActionMasked() == MotionEvent.ACTION_MOVE) {
+ // Do not allow NotificationPanelView to intercept touch events when this
+ // view can be scrolled down.
+ if (mLastMotionY >= 0 && Math.abs(ev.getY() - mLastMotionY) > mTouchSlop
+ && canScrollVertically(1)) {
+ requestParentDisallowInterceptTouchEvent(true);
+ mLastMotionY = (int) ev.getY();
+ return true;
+ }
+ } else if (ev.getActionMasked() == MotionEvent.ACTION_CANCEL
+ || ev.getActionMasked() == MotionEvent.ACTION_UP) {
+ mLastMotionY = -1;
+ requestParentDisallowInterceptTouchEvent(false);
+ }
+ return false;
+ }
+
+ private void requestParentDisallowInterceptTouchEvent(boolean disallowIntercept) {
+ final ViewParent parent = getParent();
+ if (parent != null) {
+ parent.requestDisallowInterceptTouchEvent(disallowIntercept);
+ }
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QuickQSPanel.java b/packages/SystemUI/src/com/android/systemui/qs/QuickQSPanel.java
index 947b23f..8314855 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QuickQSPanel.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QuickQSPanel.java
@@ -20,6 +20,7 @@
import android.util.AttributeSet;
import android.view.Gravity;
import android.view.View;
+import android.view.ViewGroup;
import android.widget.LinearLayout;
import android.widget.Space;
@@ -50,13 +51,14 @@
public QuickQSPanel(Context context, AttributeSet attrs) {
super(context, attrs);
if (mFooter != null) {
- removeView((View) mFooter.getView());
+ removeView(mFooter.getView());
}
if (mTileLayout != null) {
for (int i = 0; i < mRecords.size(); i++) {
mTileLayout.removeTile(mRecords.get(i));
}
- removeView((View) mTileLayout);
+ View tileLayoutView = (View) mTileLayout;
+ ((ViewGroup) tileLayoutView.getParent()).removeView(tileLayoutView);
}
mTileLayout = new HeaderTileLayout(context);
mTileLayout.setListening(mListening);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationGutsManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationGutsManager.java
index b9e6725..1aaa3b2 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationGutsManager.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationGutsManager.java
@@ -15,6 +15,9 @@
*/
package com.android.systemui.statusbar;
+import static android.service.notification.NotificationListenerService.Ranking
+ .USER_SENTIMENT_NEGATIVE;
+
import android.app.INotificationManager;
import android.app.NotificationChannel;
import android.content.Context;
@@ -230,7 +233,8 @@
try {
info.bindNotification(pmUser, iNotificationManager, pkg, row.getEntry().channel,
channels.size(), sbn, mCheckSaveListener, onSettingsClick,
- onAppSettingsClick, mNonBlockablePkgs);
+ onAppSettingsClick, mNonBlockablePkgs,
+ row.getEntry().userSentiment == USER_SENTIMENT_NEGATIVE);
} catch (RemoteException e) {
Log.e(TAG, e.toString());
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationInfo.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationInfo.java
index 6279fdc..735f4fd 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationInfo.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationInfo.java
@@ -79,6 +79,7 @@
private OnSettingsClickListener mOnSettingsClickListener;
private OnAppSettingsClickListener mAppSettingsClickListener;
private NotificationGuts mGutsContainer;
+ private boolean mNegativeUserSentiment;
private OnClickListener mOnKeepShowing = v -> {
closeControls(v);
@@ -122,6 +123,22 @@
final OnAppSettingsClickListener onAppSettingsClick,
final Set<String> nonBlockablePkgs)
throws RemoteException {
+ bindNotification(pm, iNotificationManager, pkg, notificationChannel, numChannels, sbn,
+ checkSaveListener, onSettingsClick, onAppSettingsClick, nonBlockablePkgs,
+ false /* negative sentiment */);
+ }
+
+ public void bindNotification(final PackageManager pm,
+ final INotificationManager iNotificationManager,
+ final String pkg,
+ final NotificationChannel notificationChannel,
+ final int numChannels,
+ final StatusBarNotification sbn,
+ final CheckSaveListener checkSaveListener,
+ final OnSettingsClickListener onSettingsClick,
+ final OnAppSettingsClickListener onAppSettingsClick,
+ final Set<String> nonBlockablePkgs,
+ boolean negativeUserSentiment) throws RemoteException {
mINotificationManager = iNotificationManager;
mPkg = pkg;
mNumNotificationChannels = numChannels;
@@ -133,6 +150,7 @@
mOnSettingsClickListener = onSettingsClick;
mSingleNotificationChannel = notificationChannel;
mStartingUserImportance = mChosenImportance = mSingleNotificationChannel.getImportance();
+ mNegativeUserSentiment = negativeUserSentiment;
int numTotalChannels = mINotificationManager.getNumNotificationChannelsForPackage(
pkg, mAppUid, false /* includeDeleted */);
@@ -227,27 +245,30 @@
}
private void bindPrompt() {
- final TextView channelName = findViewById(R.id.channel_name);
final TextView blockPrompt = findViewById(R.id.block_prompt);
+ bindName();
if (mNonblockable) {
- if (mIsSingleDefaultChannel || mNumNotificationChannels > 1) {
- channelName.setVisibility(View.GONE);
- } else {
- channelName.setText(mSingleNotificationChannel.getName());
- }
-
blockPrompt.setText(R.string.notification_unblockable_desc);
} else {
- if (mIsSingleDefaultChannel || mNumNotificationChannels > 1) {
- channelName.setVisibility(View.GONE);
+ if (mNegativeUserSentiment) {
+ blockPrompt.setText(R.string.inline_blocking_helper);
+ } else if (mIsSingleDefaultChannel || mNumNotificationChannels > 1) {
blockPrompt.setText(R.string.inline_keep_showing_app);
} else {
- channelName.setText(mSingleNotificationChannel.getName());
blockPrompt.setText(R.string.inline_keep_showing);
}
}
}
+ private void bindName() {
+ final TextView channelName = findViewById(R.id.channel_name);
+ if (mIsSingleDefaultChannel || mNumNotificationChannels > 1) {
+ channelName.setVisibility(View.GONE);
+ } else {
+ channelName.setText(mSingleNotificationChannel.getName());
+ }
+ }
+
private boolean hasImportanceChanged() {
return mSingleNotificationChannel != null && mStartingUserImportance != mChosenImportance;
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarFragment.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarFragment.java
index dc51b1c..61c8027 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarFragment.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarFragment.java
@@ -124,6 +124,7 @@
private AccessibilityManager mAccessibilityManager;
private MagnificationContentObserver mMagnificationObserver;
private ContentResolver mContentResolver;
+ private final MetricsLogger mMetricsLogger = Dependency.get(MetricsLogger.class);
private int mDisabledFlags1;
private StatusBar mStatusBar;
@@ -224,7 +225,7 @@
mNavigationBarView = (NavigationBarView) view;
mNavigationBarView.setDisabledFlags(mDisabledFlags1);
- mNavigationBarView.setComponents(mRecents, mDivider);
+ mNavigationBarView.setComponents(mRecents, mDivider, mStatusBar.getPanel());
mNavigationBarView.setOnVerticalChangedListener(this::onVerticalChanged);
mNavigationBarView.setOnTouchListener(this::onNavigationTouch);
if (savedInstanceState != null) {
@@ -355,6 +356,7 @@
mLastRotationSuggestion = rotation; // Remember rotation for click
setRotateSuggestionButtonState(true);
rescheduleRotationTimeout(false);
+ mMetricsLogger.visible(MetricsEvent.ROTATION_SUGGESTION_SHOWN);
}
}
@@ -612,7 +614,7 @@
if (shouldDisableNavbarGestures()) {
return false;
}
- MetricsLogger.action(getContext(), MetricsEvent.ACTION_ASSIST_LONG_PRESS);
+ mMetricsLogger.action(MetricsEvent.ACTION_ASSIST_LONG_PRESS);
mAssistManager.startAssist(new Bundle() /* args */);
mStatusBar.awakenDreams();
@@ -768,6 +770,7 @@
}
private void onRotateSuggestionClick(View v) {
+ mMetricsLogger.action(MetricsEvent.ACTION_ROTATION_SUGGESTION_ACCEPTED);
mRotationLockController.setRotationLockedAtAngle(true, mLastRotationSuggestion);
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarGestureHelper.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarGestureHelper.java
index ff923e5..0954fd0 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarGestureHelper.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarGestureHelper.java
@@ -34,6 +34,7 @@
import com.android.systemui.OverviewProxyService;
import com.android.systemui.R;
import com.android.systemui.RecentsComponent;
+import com.android.systemui.SysUiServiceProvider;
import com.android.systemui.plugins.statusbar.phone.NavGesture.GestureHelper;
import com.android.systemui.shared.recents.IOverviewProxy;
import com.android.systemui.shared.recents.utilities.Utilities;
@@ -78,6 +79,7 @@
private final int mScrollTouchSlop;
private final Matrix mTransformGlobalMatrix = new Matrix();
private final Matrix mTransformLocalMatrix = new Matrix();
+ private final StatusBar mStatusBar;
private int mTouchDownX;
private int mTouchDownY;
private boolean mDownOnRecents;
@@ -90,6 +92,7 @@
public NavigationBarGestureHelper(Context context) {
mContext = context;
+ mStatusBar = SysUiServiceProvider.getComponent(context, StatusBar.class);
Resources r = context.getResources();
mScrollTouchSlop = r.getDimensionPixelSize(R.dimen.navigation_bar_min_swipe_distance);
mQuickScrubController = new QuickScrubController(context);
@@ -146,7 +149,8 @@
break;
}
}
- if (!mQuickScrubController.onInterceptTouchEvent(event)) {
+ if (mStatusBar.isPresenterFullyCollapsed()
+ && !mQuickScrubController.onInterceptTouchEvent(event)) {
proxyMotionEvents(event);
return false;
}
@@ -304,7 +308,8 @@
}
public boolean onTouchEvent(MotionEvent event) {
- boolean result = mQuickScrubController.onTouchEvent(event) || proxyMotionEvents(event);
+ boolean result = mStatusBar.isPresenterFullyCollapsed()
+ && (mQuickScrubController.onTouchEvent(event) || proxyMotionEvents(event));
if (mDockWindowEnabled) {
result |= handleDockWindowEvent(event);
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarView.java
index 9bef0ee..9f4d35e 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarView.java
@@ -126,6 +126,7 @@
private RecentsComponent mRecentsComponent;
private Divider mDivider;
private SwipeUpOnboarding mSwipeUpOnboarding;
+ private NotificationPanelView mPanelView;
private class NavTransitionListener implements TransitionListener {
private boolean mBackTransitioning;
@@ -206,7 +207,7 @@
}
private final OverviewProxyListener mOverviewProxyListener = isConnected -> {
- setSlippery(!isConnected);
+ updateSlippery();
setDisabledFlags(mDisabledFlags, true);
setUpSwipeUpOnboarding(isConnected);
};
@@ -251,9 +252,11 @@
return mBarTransitions.getLightTransitionsController();
}
- public void setComponents(RecentsComponent recentsComponent, Divider divider) {
+ public void setComponents(RecentsComponent recentsComponent, Divider divider,
+ NotificationPanelView panel) {
mRecentsComponent = recentsComponent;
mDivider = divider;
+ mPanelView = panel;
if (mGestureHelper instanceof NavigationBarGestureHelper) {
((NavigationBarGestureHelper) mGestureHelper).setComponents(
recentsComponent, divider, this);
@@ -571,6 +574,14 @@
}
}
+ public void onPanelExpandedChange(boolean expanded) {
+ updateSlippery();
+ }
+
+ private void updateSlippery() {
+ setSlippery(mOverviewProxyService.getProxy() != null && mPanelView.isFullyExpanded());
+ }
+
private void setSlippery(boolean slippery) {
boolean changed = false;
final ViewGroup navbarView = ((ViewGroup) getParent());
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java
index 5d3cc34..31b8159 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java
@@ -47,7 +47,6 @@
import android.view.WindowInsets;
import android.view.accessibility.AccessibilityEvent;
import android.widget.FrameLayout;
-
import com.android.internal.logging.MetricsLogger;
import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
import com.android.keyguard.KeyguardStatusView;
@@ -675,7 +674,7 @@
@Override
public boolean onInterceptTouchEvent(MotionEvent event) {
- if (mBlockTouches || mQs.isCustomizing()) {
+ if (mBlockTouches || mQsFullyExpanded && mQs.onInterceptTouchEvent(event)) {
return false;
}
initDownStates(event);
@@ -2633,6 +2632,7 @@
public void setPulsing(Collection<HeadsUpManager.HeadsUpEntry> pulsing) {
mKeyguardStatusView.setPulsing(pulsing != null);
+ positionClockAndNotifications();
mNotificationStackScroller.setPulsing(pulsing, mKeyguardStatusView.getLocationOnScreen()[1]
+ mKeyguardStatusView.getClockBottom());
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarView.java
index b181212..cc5a93c 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarView.java
@@ -250,6 +250,9 @@
super.panelExpansionChanged(frac, expanded);
mPanelFraction = frac;
updateScrimFraction();
+ if ((frac == 0 || frac == 1) && mBar.getNavigationBarView() != null) {
+ mBar.getNavigationBarView().onPanelExpandedChange(expanded);
+ }
}
private void updateScrimFraction() {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/QuickScrubController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/QuickScrubController.java
index ee1d088..001a1a2 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/QuickScrubController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/QuickScrubController.java
@@ -19,6 +19,7 @@
import android.animation.Animator;
import android.animation.AnimatorListenerAdapter;
import android.animation.AnimatorSet;
+import android.animation.ArgbEvaluator;
import android.animation.ObjectAnimator;
import android.animation.ValueAnimator;
import android.animation.ValueAnimator.AnimatorUpdateListener;
@@ -82,7 +83,10 @@
private boolean mDragPositive;
private boolean mIsVertical;
private boolean mIsRTL;
- private float mMaxTrackPaintAlpha;
+ private float mTrackAlpha;
+ private int mLightTrackColor;
+ private int mDarkTrackColor;
+ private float mDarkIntensity;
private final Handler mHandler = new Handler();
private final Interpolator mQuickScrubEndInterpolator = new DecelerateInterpolator();
@@ -98,9 +102,10 @@
private final ValueAnimator mButtonAnimator;
private final AnimatorSet mQuickScrubEndAnimator;
private final Context mContext;
+ private final ArgbEvaluator mTrackColorEvaluator = new ArgbEvaluator();
private final AnimatorUpdateListener mTrackAnimatorListener = valueAnimator -> {
- mTrackPaint.setAlpha(Math.round((float) valueAnimator.getAnimatedValue() * 255));
+ mTrackAlpha = (float) valueAnimator.getAnimatedValue();
mNavigationBarView.invalidate();
};
@@ -167,6 +172,7 @@
mGestureDetector = new GestureDetector(mContext, mGestureListener);
mTrackThickness = getDimensionPixelSize(mContext, R.dimen.nav_quick_scrub_track_thickness);
mTrackPadding = getDimensionPixelSize(mContext, R.dimen.nav_quick_scrub_track_edge_padding);
+ mTrackPaint.setAlpha(0);
mTrackAnimator = ObjectAnimator.ofFloat();
mTrackAnimator.addUpdateListener(mTrackAnimatorListener);
@@ -291,6 +297,10 @@
@Override
public void onDraw(Canvas canvas) {
+ int color = (int) mTrackColorEvaluator.evaluate(mDarkIntensity, mLightTrackColor,
+ mDarkTrackColor);
+ mTrackPaint.setColor(color);
+ mTrackPaint.setAlpha((int) (mTrackPaint.getAlpha() * mTrackAlpha));
canvas.drawRect(mTrackRect, mTrackPaint);
}
@@ -326,13 +336,8 @@
@Override
public void onDarkIntensityChange(float intensity) {
- if (intensity == 0) {
- mTrackPaint.setColor(mContext.getColor(R.color.quick_step_track_background_light));
- } else if (intensity == 1) {
- mTrackPaint.setColor(mContext.getColor(R.color.quick_step_track_background_dark));
- }
- mMaxTrackPaintAlpha = mTrackPaint.getAlpha() * 1f / 255;
- mTrackPaint.setAlpha(0);
+ mDarkIntensity = intensity;
+ mNavigationBarView.invalidate();
}
@Override
@@ -365,7 +370,9 @@
private void startQuickScrub() {
if (!mQuickScrubActive) {
mQuickScrubActive = true;
- mTrackAnimator.setFloatValues(0, mMaxTrackPaintAlpha);
+ mLightTrackColor = mContext.getColor(R.color.quick_step_track_background_light);
+ mDarkTrackColor = mContext.getColor(R.color.quick_step_track_background_dark);
+ mTrackAnimator.setFloatValues(0, 1);
mTrackAnimator.start();
try {
mOverviewEventSender.getProxy().onQuickScrubStart();
@@ -382,7 +389,7 @@
mHandler.removeCallbacks(mLongPressRunnable);
if (mDraggingActive || mQuickScrubActive) {
mButtonAnimator.setIntValues((int) mTranslation, 0);
- mTrackAnimator.setFloatValues(mTrackPaint.getAlpha() * 1f / 255, 0);
+ mTrackAnimator.setFloatValues(mTrackAlpha, 0);
mQuickScrubEndAnimator.start();
try {
mOverviewEventSender.getProxy().onQuickScrubEnd();
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/LocationControllerImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/LocationControllerImpl.java
index 0b666a6..1e894ff 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/LocationControllerImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/LocationControllerImpl.java
@@ -32,6 +32,7 @@
import android.os.Process;
import android.os.UserHandle;
import android.os.UserManager;
+import android.provider.Settings;
import android.support.annotation.VisibleForTesting;
import com.android.systemui.util.Utils;
import java.util.ArrayList;
@@ -105,7 +106,8 @@
}
// When enabling location, a user consent dialog will pop up, and the
// setting won't be fully enabled until the user accepts the agreement.
- updateLocationEnabled(mContext, enabled, currentUserId);
+ updateLocationEnabled(mContext, enabled, currentUserId,
+ Settings.Secure.LOCATION_CHANGER_QUICK_SETTINGS);
return true;
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationInfoTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationInfoTest.java
index d77bf69..8e8b3e0 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationInfoTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationInfoTest.java
@@ -281,6 +281,16 @@
}
@Test
+ public void testbindNotification_BlockingHelper() throws Exception {
+ mNotificationInfo.bindNotification(mMockPackageManager, mMockINotificationManager,
+ TEST_PACKAGE_NAME, mNotificationChannel, 1, mSbn, null, null,
+ null, null, true);
+ final TextView view = mNotificationInfo.findViewById(R.id.block_prompt);
+ assertEquals(View.VISIBLE, view.getVisibility());
+ assertEquals(mContext.getString(R.string.inline_blocking_helper), view.getText());
+ }
+
+ @Test
public void testbindNotification_UnblockableTextVisibleWhenAppUnblockable() throws Exception {
mNotificationInfo.bindNotification(mMockPackageManager, mMockINotificationManager,
TEST_PACKAGE_NAME, mNotificationChannel, 1, mSbn, null, null,
diff --git a/proto/src/metrics_constants.proto b/proto/src/metrics_constants.proto
index 699231f..03dfd46 100644
--- a/proto/src/metrics_constants.proto
+++ b/proto/src/metrics_constants.proto
@@ -5158,6 +5158,16 @@
// OS: P
NOTIFICATION_ZEN_MODE_ENABLE_DIALOG = 1286;
+ // ACTION: Rotate suggestion accepted in rotation locked mode
+ // CATEGORY: GLOBAL_SYSTEM_UI
+ // OS: P
+ ACTION_ROTATION_SUGGESTION_ACCEPTED = 1287;
+
+ // OPEN: Rotation suggestion shown in rotation locked mode
+ // CATEGORY: GLOBAL_SYSTEM_UI
+ // OS: P
+ ROTATION_SUGGESTION_SHOWN = 1288;
+
// ---- End P Constants, all P constants go above this line ----
// Add new aosp constants above this line.
// END OF AOSP CONSTANTS
diff --git a/services/core/java/com/android/server/LocationManagerService.java b/services/core/java/com/android/server/LocationManagerService.java
index 9aa588f..bd93b179 100644
--- a/services/core/java/com/android/server/LocationManagerService.java
+++ b/services/core/java/com/android/server/LocationManagerService.java
@@ -67,6 +67,7 @@
import android.os.UserHandle;
import android.os.UserManager;
import android.os.WorkSource;
+import android.os.WorkSource.WorkChain;
import android.provider.Settings;
import android.text.TextUtils;
import android.util.ArrayMap;
@@ -829,7 +830,7 @@
}
mAllowedResolutionLevel = getAllowedResolutionLevel(pid, uid);
mIdentity = new Identity(uid, pid, packageName);
- if (workSource != null && workSource.size() <= 0) {
+ if (workSource != null && workSource.isEmpty()) {
workSource = null;
}
mWorkSource = workSource;
@@ -1814,13 +1815,11 @@
if (locationRequest.getInterval() <= thresholdInterval) {
if (record.mReceiver.mWorkSource != null
- && record.mReceiver.mWorkSource.size() > 0
- && record.mReceiver.mWorkSource.getName(0) != null) {
- // Assign blame to another work source.
- // Can only assign blame if the WorkSource contains names.
+ && isValidWorkSource(record.mReceiver.mWorkSource)) {
worksource.add(record.mReceiver.mWorkSource);
} else {
- // Assign blame to caller.
+ // Assign blame to caller if there's no WorkSource associated with
+ // the request or if it's invalid.
worksource.add(
record.mReceiver.mIdentity.mUid,
record.mReceiver.mIdentity.mPackageName);
@@ -1835,6 +1834,23 @@
p.setRequest(providerRequest, worksource);
}
+ /**
+ * Whether a given {@code WorkSource} associated with a Location request is valid.
+ */
+ private static boolean isValidWorkSource(WorkSource workSource) {
+ if (workSource.size() > 0) {
+ // If the WorkSource has one or more non-chained UIDs, make sure they're accompanied
+ // by tags.
+ return workSource.getName(0) != null;
+ } else {
+ // For now, make sure callers have supplied an attribution tag for use with
+ // AppOpsManager. This might be relaxed in the future.
+ final ArrayList<WorkChain> workChains = workSource.getWorkChains();
+ return workChains != null && !workChains.isEmpty() &&
+ workChains.get(0).getAttributionTag() != null;
+ }
+ }
+
@Override
public String[] getBackgroundThrottlingWhitelist() {
synchronized (mLock) {
@@ -2057,7 +2073,7 @@
checkResolutionLevelIsSufficientForProviderUse(allowedResolutionLevel,
request.getProvider());
WorkSource workSource = request.getWorkSource();
- if (workSource != null && workSource.size() > 0) {
+ if (workSource != null && !workSource.isEmpty()) {
checkDeviceStatsAllowed();
}
boolean hideFromAppOps = request.getHideFromAppOps();
diff --git a/services/core/java/com/android/server/TextServicesManagerService.java b/services/core/java/com/android/server/TextServicesManagerService.java
index 7cd3406..39fc019 100644
--- a/services/core/java/com/android/server/TextServicesManagerService.java
+++ b/services/core/java/com/android/server/TextServicesManagerService.java
@@ -701,7 +701,8 @@
protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
if (!DumpUtils.checkDumpPermission(mContext, TAG, pw)) return;
- if (args.length == 0) { // Dump all users' data
+ if (args.length == 0 || (args.length == 1 && args[0].equals("-a"))) {
+ // Dump all users' data
synchronized (mLock) {
pw.println("Current Text Services Manager state:");
pw.println(" Users:");
diff --git a/services/core/java/com/android/server/am/ActivityDisplay.java b/services/core/java/com/android/server/am/ActivityDisplay.java
index db21ef1..427ccba 100644
--- a/services/core/java/com/android/server/am/ActivityDisplay.java
+++ b/services/core/java/com/android/server/am/ActivityDisplay.java
@@ -410,7 +410,7 @@
}
} finally {
final ActivityStack topFullscreenStack =
- getStack(WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD);
+ getTopStackInWindowingMode(WINDOWING_MODE_FULLSCREEN);
if (topFullscreenStack != null && mHomeStack != null && !isTopStack(mHomeStack)) {
// Whenever split-screen is dismissed we want the home stack directly behind the
// current top fullscreen stack so it shows up when the top stack is finished.
@@ -566,6 +566,16 @@
return false;
}
+ ActivityStack getTopStackInWindowingMode(int windowingMode) {
+ for (int i = mStacks.size() - 1; i >= 0; --i) {
+ final ActivityStack current = mStacks.get(i);
+ if (windowingMode == current.getWindowingMode()) {
+ return current;
+ }
+ }
+ return null;
+ }
+
int getIndexOf(ActivityStack stack) {
return mStacks.indexOf(stack);
}
diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java
index 364d5d5..1f5bfe6 100644
--- a/services/core/java/com/android/server/am/ActivityManagerService.java
+++ b/services/core/java/com/android/server/am/ActivityManagerService.java
@@ -46,6 +46,7 @@
import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN_OR_SPLIT_SCREEN_SECONDARY;
import static android.app.WindowConfiguration.WINDOWING_MODE_PINNED;
import static android.app.WindowConfiguration.WINDOWING_MODE_SPLIT_SCREEN_PRIMARY;
+import static android.app.WindowConfiguration.WINDOWING_MODE_SPLIT_SCREEN_SECONDARY;
import static android.app.WindowConfiguration.WINDOWING_MODE_UNDEFINED;
import static android.content.Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS;
import static android.content.Intent.FLAG_ACTIVITY_NEW_TASK;
@@ -228,6 +229,7 @@
import android.app.BroadcastOptions;
import android.app.ContentProviderHolder;
import android.app.Dialog;
+import android.app.GrantedUriPermission;
import android.app.IActivityController;
import android.app.IActivityManager;
import android.app.IApplicationThread;
@@ -10204,7 +10206,8 @@
if (perms == null) {
Slog.w(TAG, "No permission grants found for " + packageName);
} else {
- for (UriPermission perm : perms.values()) {
+ for (int j = 0; j < perms.size(); j++) {
+ final UriPermission perm = perms.valueAt(j);
if (packageName.equals(perm.targetPkg) && perm.persistedModeFlags != 0) {
result.add(perm.buildPersistedPublicApiObject());
}
@@ -10215,7 +10218,8 @@
for (int i = 0; i < size; i++) {
final ArrayMap<GrantUri, UriPermission> perms =
mGrantedUriPermissions.valueAt(i);
- for (UriPermission perm : perms.values()) {
+ for (int j = 0; j < perms.size(); j++) {
+ final UriPermission perm = perms.valueAt(j);
if (packageName.equals(perm.sourcePkg) && perm.persistedModeFlags != 0) {
result.add(perm.buildPersistedPublicApiObject());
}
@@ -10227,25 +10231,27 @@
}
@Override
- public ParceledListSlice<android.content.UriPermission> getGrantedUriPermissions(
- String packageName, int userId) {
+ public ParceledListSlice<GrantedUriPermission> getGrantedUriPermissions(
+ @Nullable String packageName, int userId) {
enforceCallingPermission(android.Manifest.permission.GET_APP_GRANTED_URI_PERMISSIONS,
"getGrantedUriPermissions");
- final ArrayList<android.content.UriPermission> result = Lists.newArrayList();
+ final List<GrantedUriPermission> result = new ArrayList<>();
synchronized (this) {
final int size = mGrantedUriPermissions.size();
for (int i = 0; i < size; i++) {
final ArrayMap<GrantUri, UriPermission> perms = mGrantedUriPermissions.valueAt(i);
- for (UriPermission perm : perms.values()) {
- if (packageName.equals(perm.targetPkg) && perm.targetUserId == userId
+ for (int j = 0; j < perms.size(); j++) {
+ final UriPermission perm = perms.valueAt(j);
+ if ((packageName == null || packageName.equals(perm.targetPkg))
+ && perm.targetUserId == userId
&& perm.persistedModeFlags != 0) {
- result.add(perm.buildPersistedPublicApiObject());
+ result.add(perm.buildGrantedUriPermission());
}
}
}
}
- return new ParceledListSlice<android.content.UriPermission>(result);
+ return new ParceledListSlice<>(result);
}
@Override
@@ -11037,8 +11043,20 @@
}
if (toTop) {
+ // Caller wants the current split-screen primary stack to be the top stack after
+ // it goes fullscreen, so move it to the front.
stack.moveToFront("dismissSplitScreenMode");
+ } else if (mStackSupervisor.isFocusedStack(stack)) {
+ // In this case the current split-screen primary stack shouldn't be the top
+ // stack after it goes fullscreen, but it current has focus, so we move the
+ // focus to the top-most split-screen secondary stack next to it.
+ final ActivityStack otherStack = stack.getDisplay().getTopStackInWindowingMode(
+ WINDOWING_MODE_SPLIT_SCREEN_SECONDARY);
+ if (otherStack != null) {
+ otherStack.moveToFront("dismissSplitScreenMode_other");
+ }
}
+
stack.setWindowingMode(WINDOWING_MODE_FULLSCREEN);
}
} finally {
diff --git a/services/core/java/com/android/server/am/BatteryStatsService.java b/services/core/java/com/android/server/am/BatteryStatsService.java
index 04b49ba..0d96468 100644
--- a/services/core/java/com/android/server/am/BatteryStatsService.java
+++ b/services/core/java/com/android/server/am/BatteryStatsService.java
@@ -16,6 +16,7 @@
package com.android.server.am;
+import android.app.ActivityManager;
import android.bluetooth.BluetoothActivityEnergyInfo;
import android.content.Context;
import android.content.pm.ApplicationInfo;
@@ -353,10 +354,12 @@
}
}
+ /** @param state Process state from ActivityManager.java. */
void noteUidProcessState(int uid, int state) {
synchronized (mStats) {
// TODO: remove this once we figure out properly where and how
- StatsLog.write(StatsLog.UID_PROCESS_STATE_CHANGED, uid, state);
+ StatsLog.write(StatsLog.UID_PROCESS_STATE_CHANGED, uid,
+ ActivityManager.processStateAmToProto(state));
mStats.noteUidProcessStateLocked(uid, state);
}
@@ -582,17 +585,11 @@
}
}
- public void noteStartGps(int uid) {
+ @Override
+ public void noteGpsChanged(WorkSource oldWs, WorkSource newWs) {
enforceCallingPermission();
synchronized (mStats) {
- mStats.noteStartGpsLocked(uid);
- }
- }
-
- public void noteStopGps(int uid) {
- enforceCallingPermission();
- synchronized (mStats) {
- mStats.noteStopGpsLocked(uid);
+ mStats.noteGpsChangedLocked(oldWs, newWs);
}
}
diff --git a/services/core/java/com/android/server/am/ProcessList.java b/services/core/java/com/android/server/am/ProcessList.java
index 29bfebe..a50d069 100644
--- a/services/core/java/com/android/server/am/ProcessList.java
+++ b/services/core/java/com/android/server/am/ProcessList.java
@@ -24,7 +24,7 @@
import java.nio.ByteBuffer;
import android.app.ActivityManager;
-import android.app.ActivityManagerProto;
+import android.app.AppProtoEnums;
import android.os.Build;
import android.os.SystemClock;
import com.android.internal.util.MemInfoReader;
@@ -420,47 +420,49 @@
public static int makeProcStateProtoEnum(int curProcState) {
switch (curProcState) {
case ActivityManager.PROCESS_STATE_PERSISTENT:
- return ActivityManagerProto.PROCESS_STATE_PERSISTENT;
+ return AppProtoEnums.PROCESS_STATE_PERSISTENT;
case ActivityManager.PROCESS_STATE_PERSISTENT_UI:
- return ActivityManagerProto.PROCESS_STATE_PERSISTENT_UI;
+ return AppProtoEnums.PROCESS_STATE_PERSISTENT_UI;
case ActivityManager.PROCESS_STATE_TOP:
- return ActivityManagerProto.PROCESS_STATE_TOP;
+ return AppProtoEnums.PROCESS_STATE_TOP;
case ActivityManager.PROCESS_STATE_BOUND_FOREGROUND_SERVICE:
- return ActivityManagerProto.PROCESS_STATE_BOUND_FOREGROUND_SERVICE;
+ return AppProtoEnums.PROCESS_STATE_BOUND_FOREGROUND_SERVICE;
case ActivityManager.PROCESS_STATE_FOREGROUND_SERVICE:
- return ActivityManagerProto.PROCESS_STATE_FOREGROUND_SERVICE;
+ return AppProtoEnums.PROCESS_STATE_FOREGROUND_SERVICE;
case ActivityManager.PROCESS_STATE_TOP_SLEEPING:
- return ActivityManagerProto.PROCESS_STATE_TOP_SLEEPING;
+ return AppProtoEnums.PROCESS_STATE_TOP_SLEEPING;
case ActivityManager.PROCESS_STATE_IMPORTANT_FOREGROUND:
- return ActivityManagerProto.PROCESS_STATE_IMPORTANT_FOREGROUND;
+ return AppProtoEnums.PROCESS_STATE_IMPORTANT_FOREGROUND;
case ActivityManager.PROCESS_STATE_IMPORTANT_BACKGROUND:
- return ActivityManagerProto.PROCESS_STATE_IMPORTANT_BACKGROUND;
+ return AppProtoEnums.PROCESS_STATE_IMPORTANT_BACKGROUND;
case ActivityManager.PROCESS_STATE_TRANSIENT_BACKGROUND:
- return ActivityManagerProto.PROCESS_STATE_TRANSIENT_BACKGROUND;
+ return AppProtoEnums.PROCESS_STATE_TRANSIENT_BACKGROUND;
case ActivityManager.PROCESS_STATE_BACKUP:
- return ActivityManagerProto.PROCESS_STATE_BACKUP;
+ return AppProtoEnums.PROCESS_STATE_BACKUP;
case ActivityManager.PROCESS_STATE_HEAVY_WEIGHT:
- return ActivityManagerProto.PROCESS_STATE_HEAVY_WEIGHT;
+ return AppProtoEnums.PROCESS_STATE_HEAVY_WEIGHT;
case ActivityManager.PROCESS_STATE_SERVICE:
- return ActivityManagerProto.PROCESS_STATE_SERVICE;
+ return AppProtoEnums.PROCESS_STATE_SERVICE;
case ActivityManager.PROCESS_STATE_RECEIVER:
- return ActivityManagerProto.PROCESS_STATE_RECEIVER;
+ return AppProtoEnums.PROCESS_STATE_RECEIVER;
case ActivityManager.PROCESS_STATE_HOME:
- return ActivityManagerProto.PROCESS_STATE_HOME;
+ return AppProtoEnums.PROCESS_STATE_HOME;
case ActivityManager.PROCESS_STATE_LAST_ACTIVITY:
- return ActivityManagerProto.PROCESS_STATE_LAST_ACTIVITY;
+ return AppProtoEnums.PROCESS_STATE_LAST_ACTIVITY;
case ActivityManager.PROCESS_STATE_CACHED_ACTIVITY:
- return ActivityManagerProto.PROCESS_STATE_CACHED_ACTIVITY;
+ return AppProtoEnums.PROCESS_STATE_CACHED_ACTIVITY;
case ActivityManager.PROCESS_STATE_CACHED_ACTIVITY_CLIENT:
- return ActivityManagerProto.PROCESS_STATE_CACHED_ACTIVITY_CLIENT;
+ return AppProtoEnums.PROCESS_STATE_CACHED_ACTIVITY_CLIENT;
case ActivityManager.PROCESS_STATE_CACHED_RECENT:
- return ActivityManagerProto.PROCESS_STATE_CACHED_RECENT;
+ return AppProtoEnums.PROCESS_STATE_CACHED_RECENT;
case ActivityManager.PROCESS_STATE_CACHED_EMPTY:
- return ActivityManagerProto.PROCESS_STATE_CACHED_EMPTY;
+ return AppProtoEnums.PROCESS_STATE_CACHED_EMPTY;
case ActivityManager.PROCESS_STATE_NONEXISTENT:
- return ActivityManagerProto.PROCESS_STATE_NONEXISTENT;
+ return AppProtoEnums.PROCESS_STATE_NONEXISTENT;
+ case ActivityManager.PROCESS_STATE_UNKNOWN:
+ return AppProtoEnums.PROCESS_STATE_UNKNOWN;
default:
- return -1;
+ return AppProtoEnums.PROCESS_STATE_UNKNOWN_TO_PROTO;
}
}
diff --git a/services/core/java/com/android/server/am/UriPermission.java b/services/core/java/com/android/server/am/UriPermission.java
index 90577e3..1e071aa 100644
--- a/services/core/java/com/android/server/am/UriPermission.java
+++ b/services/core/java/com/android/server/am/UriPermission.java
@@ -16,6 +16,7 @@
package com.android.server.am;
+import android.app.GrantedUriPermission;
import android.content.Intent;
import android.os.Binder;
import android.os.UserHandle;
@@ -387,4 +388,8 @@
public android.content.UriPermission buildPersistedPublicApiObject() {
return new android.content.UriPermission(uri.uri, persistedModeFlags, persistedCreateTime);
}
+
+ public GrantedUriPermission buildGrantedUriPermission() {
+ return new GrantedUriPermission(uri.uri, targetPkg);
+ }
}
diff --git a/services/core/java/com/android/server/broadcastradio/hal1/Tuner.java b/services/core/java/com/android/server/broadcastradio/hal1/Tuner.java
index f9b35f5..e77cb7a 100644
--- a/services/core/java/com/android/server/broadcastradio/hal1/Tuner.java
+++ b/services/core/java/com/android/server/broadcastradio/hal1/Tuner.java
@@ -48,7 +48,7 @@
private boolean mIsClosed = false;
private boolean mIsMuted = false;
- private int mRegion; // TODO(b/62710330): find better solution to handle regions
+ private int mRegion;
private final boolean mWithAudio;
Tuner(@NonNull ITunerCallback clientCallback, int halRev,
@@ -89,7 +89,6 @@
private native void nativeCancelAnnouncement(long nativeContext);
- private native RadioManager.ProgramInfo nativeGetProgramInformation(long nativeContext);
private native boolean nativeStartBackgroundScan(long nativeContext);
private native List<RadioManager.ProgramInfo> nativeGetProgramList(long nativeContext,
Map<String, String> vendorFilter);
@@ -103,8 +102,6 @@
Map<String, String> parameters);
private native Map<String, String> nativeGetParameters(long nativeContext, List<String> keys);
- private native boolean nativeIsAntennaConnected(long nativeContext);
-
@Override
public void close() {
synchronized (mLock) {
@@ -218,14 +215,6 @@
}
@Override
- public RadioManager.ProgramInfo getProgramInformation() {
- synchronized (mLock) {
- checkNotClosedLocked();
- return nativeGetProgramInformation(mNativeContext);
- }
- }
-
- @Override
public Bitmap getImage(int id) {
if (id == 0) {
throw new IllegalArgumentException("Image ID is missing");
@@ -324,12 +313,4 @@
if (results == null) return Collections.emptyMap();
return results;
}
-
- @Override
- public boolean isAntennaConnected() {
- synchronized (mLock) {
- checkNotClosedLocked();
- return nativeIsAntennaConnected(mNativeContext);
- }
- }
}
diff --git a/services/core/java/com/android/server/broadcastradio/hal1/TunerCallback.java b/services/core/java/com/android/server/broadcastradio/hal1/TunerCallback.java
index 18f56ed..04c0e57 100644
--- a/services/core/java/com/android/server/broadcastradio/hal1/TunerCallback.java
+++ b/services/core/java/com/android/server/broadcastradio/hal1/TunerCallback.java
@@ -20,6 +20,7 @@
import android.hardware.radio.ITuner;
import android.hardware.radio.ITunerCallback;
import android.hardware.radio.ProgramList;
+import android.hardware.radio.ProgramSelector;
import android.hardware.radio.RadioManager;
import android.hardware.radio.RadioMetadata;
import android.hardware.radio.RadioTuner;
@@ -100,6 +101,11 @@
}
@Override
+ public void onTuneFailed(int result, ProgramSelector selector) {
+ Slog.e(TAG, "Not applicable for HAL 1.x");
+ }
+
+ @Override
public void onConfigurationChanged(RadioManager.BandConfig config) {
dispatch(() -> mClientCallback.onConfigurationChanged(config));
}
diff --git a/services/core/java/com/android/server/broadcastradio/hal2/Convert.java b/services/core/java/com/android/server/broadcastradio/hal2/Convert.java
index 7a95971..3bb3d1f 100644
--- a/services/core/java/com/android/server/broadcastradio/hal2/Convert.java
+++ b/services/core/java/com/android/server/broadcastradio/hal2/Convert.java
@@ -73,7 +73,26 @@
}
}
- private static @NonNull Map<String, String>
+ static @NonNull ArrayList<VendorKeyValue>
+ vendorInfoToHal(@Nullable Map<String, String> info) {
+ if (info == null) return new ArrayList<>();
+
+ ArrayList<VendorKeyValue> list = new ArrayList<>();
+ for (Map.Entry<String, String> entry : info.entrySet()) {
+ VendorKeyValue elem = new VendorKeyValue();
+ elem.key = entry.getKey();
+ elem.value = entry.getValue();
+ if (elem.key == null || elem.value == null) {
+ Slog.w(TAG, "VendorKeyValue contains null pointers");
+ continue;
+ }
+ list.add(elem);
+ }
+
+ return list;
+ }
+
+ static @NonNull Map<String, String>
vendorInfoFromHal(@Nullable List<VendorKeyValue> info) {
if (info == null) return Collections.emptyMap();
@@ -206,18 +225,23 @@
false, // isCaptureSupported
amfmConfigToBands(amfmConfig),
- false, // isBgScanSupported is deprecated
+ true, // isBgScanSupported is deprecated
supportedProgramTypes,
supportedIdentifierTypes,
vendorInfoFromHal(prop.vendorInfo)
);
}
+ static void programIdentifierToHal(@NonNull ProgramIdentifier hwId,
+ @NonNull ProgramSelector.Identifier id) {
+ hwId.type = id.getType();
+ hwId.value = id.getValue();
+ }
+
static @NonNull ProgramIdentifier programIdentifierToHal(
@NonNull ProgramSelector.Identifier id) {
ProgramIdentifier hwId = new ProgramIdentifier();
- hwId.type = id.getType();
- hwId.value = id.getValue();
+ programIdentifierToHal(hwId, id);
return hwId;
}
@@ -227,10 +251,22 @@
return new ProgramSelector.Identifier(id.type, id.value);
}
+ static @NonNull android.hardware.broadcastradio.V2_0.ProgramSelector programSelectorToHal(
+ @NonNull ProgramSelector sel) {
+ android.hardware.broadcastradio.V2_0.ProgramSelector hwSel =
+ new android.hardware.broadcastradio.V2_0.ProgramSelector();
+
+ programIdentifierToHal(hwSel.primaryId, sel.getPrimaryId());
+ Arrays.stream(sel.getSecondaryIds()).map(Convert::programIdentifierToHal).
+ forEachOrdered(hwSel.secondaryIds::add);
+
+ return hwSel;
+ }
+
static @NonNull ProgramSelector programSelectorFromHal(
@NonNull android.hardware.broadcastradio.V2_0.ProgramSelector sel) {
ProgramSelector.Identifier[] secondaryIds = sel.secondaryIds.stream().
- map(id -> Objects.requireNonNull(programIdentifierFromHal(id))).
+ map(Convert::programIdentifierFromHal).map(Objects::requireNonNull).
toArray(ProgramSelector.Identifier[]::new);
return new ProgramSelector(
@@ -286,4 +322,10 @@
vendorInfoFromHal(hwAnnouncement.vendorInfo)
);
}
+
+ static <T> @Nullable ArrayList<T> listToArrayList(@Nullable List<T> list) {
+ if (list == null) return null;
+ if (list instanceof ArrayList) return (ArrayList) list;
+ return new ArrayList<>(list);
+ }
}
diff --git a/services/core/java/com/android/server/broadcastradio/hal2/RadioModule.java b/services/core/java/com/android/server/broadcastradio/hal2/RadioModule.java
index 4dff9e0..50f032d 100644
--- a/services/core/java/com/android/server/broadcastradio/hal2/RadioModule.java
+++ b/services/core/java/com/android/server/broadcastradio/hal2/RadioModule.java
@@ -18,6 +18,8 @@
import android.annotation.NonNull;
import android.annotation.Nullable;
+import android.graphics.Bitmap;
+import android.graphics.BitmapFactory;
import android.hardware.radio.ITuner;
import android.hardware.radio.RadioManager;
import android.hardware.broadcastradio.V2_0.AmFmRegionConfig;
@@ -76,15 +78,17 @@
Mutable<ITunerSession> hwSession = new Mutable<>();
MutableInt halResult = new MutableInt(Result.UNKNOWN_ERROR);
- mService.openSession(cb, (int result, ITunerSession session) -> {
- hwSession.value = session;
- halResult.value = result;
- });
+ synchronized (mService) {
+ mService.openSession(cb, (result, session) -> {
+ hwSession.value = session;
+ halResult.value = result;
+ });
+ }
Convert.throwOnError("openSession", halResult.value);
Objects.requireNonNull(hwSession.value);
- return new TunerSession(hwSession.value, cb);
+ return new TunerSession(this, hwSession.value, cb);
}
public android.hardware.radio.ICloseHandle addAnnouncementListener(@NonNull int[] enabledTypes,
@@ -103,10 +107,13 @@
map(a -> Convert.announcementFromHal(a)).collect(Collectors.toList()));
}
};
- mService.registerAnnouncementListener(enabledList, hwListener, (result, closeHandle) -> {
- halResult.value = result;
- hwCloseHandle.value = closeHandle;
- });
+
+ synchronized (mService) {
+ mService.registerAnnouncementListener(enabledList, hwListener, (result, closeHnd) -> {
+ halResult.value = result;
+ hwCloseHandle.value = closeHnd;
+ });
+ }
Convert.throwOnError("addAnnouncementListener", halResult.value);
return new android.hardware.radio.ICloseHandle.Stub() {
@@ -119,4 +126,21 @@
}
};
}
+
+ Bitmap getImage(int id) {
+ if (id == 0) throw new IllegalArgumentException("Image ID is missing");
+
+ byte[] rawImage;
+ synchronized (mService) {
+ List<Byte> rawList = Utils.maybeRethrow(() -> mService.getImage(id));
+ rawImage = new byte[rawList.size()];
+ for (int i = 0; i < rawList.size(); i++) {
+ rawImage[i] = rawList.get(i);
+ }
+ }
+
+ if (rawImage == null || rawImage.length == 0) return null;
+
+ return BitmapFactory.decodeByteArray(rawImage, 0, rawImage.length);
+ }
}
diff --git a/services/core/java/com/android/server/broadcastradio/hal2/TunerCallback.java b/services/core/java/com/android/server/broadcastradio/hal2/TunerCallback.java
index ed2a1b3..3c4b49c 100644
--- a/services/core/java/com/android/server/broadcastradio/hal2/TunerCallback.java
+++ b/services/core/java/com/android/server/broadcastradio/hal2/TunerCallback.java
@@ -50,10 +50,14 @@
}
@Override
- public void onTuneFailed(int result, ProgramSelector selector) {}
+ public void onTuneFailed(int result, ProgramSelector selector) {
+ dispatch(() -> mClientCb.onTuneFailed(result, Convert.programSelectorFromHal(selector)));
+ }
@Override
- public void onCurrentProgramInfoChanged(ProgramInfo info) {}
+ public void onCurrentProgramInfoChanged(ProgramInfo info) {
+ dispatch(() -> mClientCb.onCurrentProgramInfoChanged(Convert.programInfoFromHal(info)));
+ }
@Override
public void onProgramListUpdated(ProgramListChunk chunk) {
@@ -61,8 +65,12 @@
}
@Override
- public void onAntennaStateChange(boolean connected) {}
+ public void onAntennaStateChange(boolean connected) {
+ dispatch(() -> mClientCb.onAntennaState(connected));
+ }
@Override
- public void onParametersUpdated(ArrayList<VendorKeyValue> parameters) {}
+ public void onParametersUpdated(ArrayList<VendorKeyValue> parameters) {
+ dispatch(() -> mClientCb.onParametersUpdated(Convert.vendorInfoFromHal(parameters)));
+ }
}
diff --git a/services/core/java/com/android/server/broadcastradio/hal2/TunerSession.java b/services/core/java/com/android/server/broadcastradio/hal2/TunerSession.java
index 1ae7d20..8efaa2a 100644
--- a/services/core/java/com/android/server/broadcastradio/hal2/TunerSession.java
+++ b/services/core/java/com/android/server/broadcastradio/hal2/TunerSession.java
@@ -41,6 +41,7 @@
private final Object mLock = new Object();
+ private final RadioModule mModule;
private final ITunerSession mHwSession;
private final TunerCallback mCallback;
private boolean mIsClosed = false;
@@ -50,7 +51,9 @@
// necessary only for older APIs compatibility
private RadioManager.BandConfig mDummyConfig = null;
- TunerSession(@NonNull ITunerSession hwSession, @NonNull TunerCallback callback) {
+ TunerSession(@NonNull RadioModule module, @NonNull ITunerSession hwSession,
+ @NonNull TunerCallback callback) {
+ mModule = Objects.requireNonNull(module);
mHwSession = Objects.requireNonNull(hwSession);
mCallback = Objects.requireNonNull(callback);
notifyAudioServiceLocked(true);
@@ -128,23 +131,29 @@
}
@Override
- public void step(boolean directionDown, boolean skipSubChannel) {
+ public void step(boolean directionDown, boolean skipSubChannel) throws RemoteException {
synchronized (mLock) {
checkNotClosedLocked();
+ int halResult = mHwSession.step(!directionDown);
+ Convert.throwOnError("step", halResult);
}
}
@Override
- public void scan(boolean directionDown, boolean skipSubChannel) {
+ public void scan(boolean directionDown, boolean skipSubChannel) throws RemoteException {
synchronized (mLock) {
checkNotClosedLocked();
+ int halResult = mHwSession.scan(!directionDown, skipSubChannel);
+ Convert.throwOnError("step", halResult);
}
}
@Override
- public void tune(ProgramSelector selector) {
+ public void tune(ProgramSelector selector) throws RemoteException {
synchronized (mLock) {
checkNotClosedLocked();
+ int halResult = mHwSession.tune(Convert.programSelectorToHal(selector));
+ Convert.throwOnError("tune", halResult);
}
}
@@ -152,36 +161,25 @@
public void cancel() {
synchronized (mLock) {
checkNotClosedLocked();
+ Utils.maybeRethrow(mHwSession::cancel);
}
}
@Override
public void cancelAnnouncement() {
- synchronized (mLock) {
- checkNotClosedLocked();
- }
- }
-
- @Override
- public RadioManager.ProgramInfo getProgramInformation() {
- synchronized (mLock) {
- checkNotClosedLocked();
- return null;
- }
+ Slog.i(TAG, "Announcements control doesn't involve cancelling at the HAL level in 2.x");
}
@Override
public Bitmap getImage(int id) {
- synchronized (mLock) {
- checkNotClosedLocked();
- return null;
- }
+ return mModule.getImage(id);
}
@Override
public boolean startBackgroundScan() {
Slog.i(TAG, "Explicit background scan trigger is not supported with HAL 2.x");
- return false;
+ TunerCallback.dispatch(() -> mCallback.mClientCb.onBackgroundScanComplete());
+ return true;
}
@Override
@@ -240,7 +238,6 @@
Slog.v(TAG, "setConfigFlag " + ConfigFlag.toString(flag) + " = " + value);
synchronized (mLock) {
checkNotClosedLocked();
-
int halResult = mHwSession.setConfigFlag(flag, value);
Convert.throwOnError("setConfigFlag", halResult);
}
@@ -250,7 +247,8 @@
public Map setParameters(Map parameters) {
synchronized (mLock) {
checkNotClosedLocked();
- return null;
+ return Convert.vendorInfoFromHal(Utils.maybeRethrow(
+ () -> mHwSession.setParameters(Convert.vendorInfoToHal(parameters))));
}
}
@@ -258,15 +256,8 @@
public Map getParameters(List<String> keys) {
synchronized (mLock) {
checkNotClosedLocked();
- return null;
- }
- }
-
- @Override
- public boolean isAntennaConnected() {
- synchronized (mLock) {
- checkNotClosedLocked();
- return true;
+ return Convert.vendorInfoFromHal(Utils.maybeRethrow(
+ () -> mHwSession.getParameters(Convert.listToArrayList(keys))));
}
}
}
diff --git a/services/core/java/com/android/server/broadcastradio/hal2/Utils.java b/services/core/java/com/android/server/broadcastradio/hal2/Utils.java
index 3520f37..384c9ba 100644
--- a/services/core/java/com/android/server/broadcastradio/hal2/Utils.java
+++ b/services/core/java/com/android/server/broadcastradio/hal2/Utils.java
@@ -16,6 +16,9 @@
package com.android.server.broadcastradio.hal2;
+import android.annotation.NonNull;
+import android.os.RemoteException;
+
enum FrequencyBand {
UNKNOWN,
FM,
@@ -37,4 +40,29 @@
if (freq < 110000) return FrequencyBand.FM;
return FrequencyBand.UNKNOWN;
}
+
+ interface FuncThrowingRemoteException<T> {
+ T exec() throws RemoteException;
+ }
+
+ static <T> T maybeRethrow(@NonNull FuncThrowingRemoteException<T> r) {
+ try {
+ return r.exec();
+ } catch (RemoteException ex) {
+ ex.rethrowFromSystemServer();
+ return null; // unreachable
+ }
+ }
+
+ interface VoidFuncThrowingRemoteException {
+ void exec() throws RemoteException;
+ }
+
+ static void maybeRethrow(@NonNull VoidFuncThrowingRemoteException r) {
+ try {
+ r.exec();
+ } catch (RemoteException ex) {
+ ex.rethrowFromSystemServer();
+ }
+ }
}
diff --git a/services/core/java/com/android/server/content/SyncManager.java b/services/core/java/com/android/server/content/SyncManager.java
index ad2cf6c..422d0cb 100644
--- a/services/core/java/com/android/server/content/SyncManager.java
+++ b/services/core/java/com/android/server/content/SyncManager.java
@@ -20,6 +20,8 @@
import android.accounts.AccountAndUser;
import android.accounts.AccountManager;
import android.accounts.AccountManagerInternal;
+import android.annotation.NonNull;
+import android.annotation.UserIdInt;
import android.app.ActivityManager;
import android.app.AppGlobals;
import android.app.Notification;
@@ -32,6 +34,7 @@
import android.content.ContentResolver;
import android.content.Context;
import android.content.ISyncAdapter;
+import android.content.ISyncAdapterUnsyncableAccountCallback;
import android.content.ISyncContext;
import android.content.Intent;
import android.content.IntentFilter;
@@ -212,6 +215,10 @@
private static final int SYNC_OP_STATE_INVALID = 1;
private static final int SYNC_OP_STATE_INVALID_NO_ACCOUNT_ACCESS = 2;
+ /** Flags used when connecting to a sync adapter service */
+ private static final int SYNC_ADAPTER_CONNECTION_FLAGS = Context.BIND_AUTO_CREATE
+ | Context.BIND_NOT_FOREGROUND | Context.BIND_ALLOW_OOM_MANAGEMENT;
+
private Context mContext;
private static final AccountAndUser[] INITIAL_ACCOUNTS_ARRAY = new AccountAndUser[0];
@@ -876,7 +883,7 @@
public void scheduleSync(Account requestedAccount, int userId, int reason,
String requestedAuthority, Bundle extras, int targetSyncState) {
scheduleSync(requestedAccount, userId, reason, requestedAuthority, extras, targetSyncState,
- 0 /* min delay */);
+ 0 /* min delay */, true /* checkIfAccountReady */);
}
/**
@@ -884,7 +891,7 @@
*/
private void scheduleSync(Account requestedAccount, int userId, int reason,
String requestedAuthority, Bundle extras, int targetSyncState,
- final long minDelayMillis) {
+ final long minDelayMillis, boolean checkIfAccountReady) {
final boolean isLoggable = Log.isLoggable(TAG, Log.VERBOSE);
if (extras == null) {
extras = new Bundle();
@@ -963,7 +970,8 @@
}
for (String authority : syncableAuthorities) {
- int isSyncable = computeSyncable(account.account, account.userId, authority);
+ int isSyncable = computeSyncable(account.account, account.userId, authority,
+ !checkIfAccountReady);
if (isSyncable == AuthorityInfo.NOT_SYNCABLE) {
continue;
@@ -1000,7 +1008,8 @@
if (result != null
&& result.getBoolean(AccountManager.KEY_BOOLEAN_RESULT)) {
scheduleSync(account.account, userId, reason, authority,
- finalExtras, targetSyncState, minDelayMillis);
+ finalExtras, targetSyncState, minDelayMillis,
+ true /* checkIfAccountReady */);
}
}
));
@@ -1009,7 +1018,7 @@
final boolean allowParallelSyncs = syncAdapterInfo.type.allowParallelSyncs();
final boolean isAlwaysSyncable = syncAdapterInfo.type.isAlwaysSyncable();
- if (isSyncable < 0 && isAlwaysSyncable) {
+ if (!checkIfAccountReady && isSyncable < 0 && isAlwaysSyncable) {
mSyncStorageEngine.setIsSyncable(
account.account, account.userId, authority, AuthorityInfo.SYNCABLE);
isSyncable = AuthorityInfo.SYNCABLE;
@@ -1045,25 +1054,34 @@
final String owningPackage = syncAdapterInfo.componentName.getPackageName();
if (isSyncable == AuthorityInfo.NOT_INITIALIZED) {
- // Initialisation sync.
- Bundle newExtras = new Bundle();
- newExtras.putBoolean(ContentResolver.SYNC_EXTRAS_INITIALIZE, true);
- if (isLoggable) {
- Slog.v(TAG, "schedule initialisation Sync:"
- + ", delay until " + delayUntil
- + ", run by " + 0
- + ", flexMillis " + 0
- + ", source " + source
- + ", account " + account
- + ", authority " + authority
- + ", extras " + newExtras);
+ if (checkIfAccountReady) {
+ Bundle finalExtras = new Bundle(extras);
+
+ sendOnUnsyncableAccount(mContext, syncAdapterInfo, account.userId,
+ () -> scheduleSync(account.account, account.userId, reason,
+ authority, finalExtras, targetSyncState, minDelayMillis,
+ false));
+ } else {
+ // Initialisation sync.
+ Bundle newExtras = new Bundle();
+ newExtras.putBoolean(ContentResolver.SYNC_EXTRAS_INITIALIZE, true);
+ if (isLoggable) {
+ Slog.v(TAG, "schedule initialisation Sync:"
+ + ", delay until " + delayUntil
+ + ", run by " + 0
+ + ", flexMillis " + 0
+ + ", source " + source
+ + ", account " + account
+ + ", authority " + authority
+ + ", extras " + newExtras);
+ }
+ postScheduleSyncMessage(
+ new SyncOperation(account.account, account.userId,
+ owningUid, owningPackage, reason, source,
+ authority, newExtras, allowParallelSyncs),
+ minDelayMillis
+ );
}
- postScheduleSyncMessage(
- new SyncOperation(account.account, account.userId,
- owningUid, owningPackage, reason, source,
- authority, newExtras, allowParallelSyncs),
- minDelayMillis
- );
} else if (targetSyncState == AuthorityInfo.UNDEFINED
|| targetSyncState == isSyncable) {
if (isLoggable) {
@@ -1085,10 +1103,6 @@
}
}
- private int computeSyncable(Account account, int userId, String authority) {
- return computeSyncable(account, userId, authority, true);
- }
-
public int computeSyncable(Account account, int userId, String authority,
boolean checkAccountAccess) {
final int status = getIsSyncable(account, userId, authority);
@@ -1198,7 +1212,7 @@
final Bundle extras = new Bundle();
extras.putBoolean(ContentResolver.SYNC_EXTRAS_UPLOAD, true);
scheduleSync(account, userId, reason, authority, extras,
- AuthorityInfo.UNDEFINED, LOCAL_SYNC_DELAY);
+ AuthorityInfo.UNDEFINED, LOCAL_SYNC_DELAY, true /* checkIfAccountReady */);
}
public SyncAdapterType[] getSyncAdapterTypes(int userId) {
@@ -1706,6 +1720,28 @@
}
/**
+ * Construct intent used to bind to an adapter.
+ *
+ * @param context Context to create intent for
+ * @param syncAdapterComponent The adapter description
+ * @param userId The user the adapter belongs to
+ *
+ * @return The intent required to bind to the adapter
+ */
+ static @NonNull Intent getAdapterBindIntent(@NonNull Context context,
+ @NonNull ComponentName syncAdapterComponent, @UserIdInt int userId) {
+ final Intent intent = new Intent();
+ intent.setAction("android.content.SyncAdapter");
+ intent.setComponent(syncAdapterComponent);
+ intent.putExtra(Intent.EXTRA_CLIENT_LABEL,
+ com.android.internal.R.string.sync_binding_label);
+ intent.putExtra(Intent.EXTRA_CLIENT_INTENT, PendingIntent.getActivityAsUser(context, 0,
+ new Intent(Settings.ACTION_SYNC_SETTINGS), 0, null, UserHandle.of(userId)));
+
+ return intent;
+ }
+
+ /**
* @hide
*/
class ActiveSyncContext extends ISyncContext.Stub
@@ -1793,19 +1829,11 @@
if (Log.isLoggable(TAG, Log.VERBOSE)) {
Log.d(TAG, "bindToSyncAdapter: " + serviceComponent + ", connection " + this);
}
- Intent intent = new Intent();
- intent.setAction("android.content.SyncAdapter");
- intent.setComponent(serviceComponent);
- intent.putExtra(Intent.EXTRA_CLIENT_LABEL,
- com.android.internal.R.string.sync_binding_label);
- intent.putExtra(Intent.EXTRA_CLIENT_INTENT, PendingIntent.getActivityAsUser(
- mContext, 0, new Intent(Settings.ACTION_SYNC_SETTINGS), 0,
- null, new UserHandle(userId)));
+ Intent intent = getAdapterBindIntent(mContext, serviceComponent, userId);
+
mBound = true;
final boolean bindResult = mContext.bindServiceAsUser(intent, this,
- Context.BIND_AUTO_CREATE | Context.BIND_NOT_FOREGROUND
- | Context.BIND_ALLOW_OOM_MANAGEMENT,
- new UserHandle(mSyncOperation.target.userId));
+ SYNC_ADAPTER_CONNECTION_FLAGS, new UserHandle(mSyncOperation.target.userId));
mLogger.log("bindService() returned=", mBound, " for ", this);
if (!bindResult) {
mBound = false;
@@ -2528,6 +2556,92 @@
}
}
+ interface OnReadyCallback {
+ void onReady();
+ }
+
+ static void sendOnUnsyncableAccount(@NonNull Context context,
+ @NonNull RegisteredServicesCache.ServiceInfo<SyncAdapterType> syncAdapterInfo,
+ @UserIdInt int userId, @NonNull OnReadyCallback onReadyCallback) {
+ OnUnsyncableAccountCheck connection = new OnUnsyncableAccountCheck(syncAdapterInfo,
+ onReadyCallback);
+
+ boolean isBound = context.bindServiceAsUser(
+ getAdapterBindIntent(context, syncAdapterInfo.componentName, userId),
+ connection, SYNC_ADAPTER_CONNECTION_FLAGS, UserHandle.of(userId));
+
+ if (isBound) {
+ // Unbind after SERVICE_BOUND_TIME_MILLIS to not leak the connection.
+ (new Handler(Looper.getMainLooper())).postDelayed(
+ () -> context.unbindService(connection),
+ OnUnsyncableAccountCheck.SERVICE_BOUND_TIME_MILLIS);
+ } else {
+ /*
+ * The default implementation of adapter.onUnsyncableAccount returns true. Hence if
+ * there the service cannot be bound, assume the default behavior.
+ */
+ connection.onReady();
+ }
+ }
+
+
+ /**
+ * Helper class for calling ISyncAdapter.onUnsyncableAccountDone.
+ *
+ * If this returns {@code true} the onReadyCallback is called. Otherwise nothing happens.
+ */
+ private static class OnUnsyncableAccountCheck implements ServiceConnection {
+ static final long SERVICE_BOUND_TIME_MILLIS = 5000;
+
+ private final @NonNull OnReadyCallback mOnReadyCallback;
+ private final @NonNull RegisteredServicesCache.ServiceInfo<SyncAdapterType>
+ mSyncAdapterInfo;
+
+ OnUnsyncableAccountCheck(
+ @NonNull RegisteredServicesCache.ServiceInfo<SyncAdapterType> syncAdapterInfo,
+ @NonNull OnReadyCallback onReadyCallback) {
+ mSyncAdapterInfo = syncAdapterInfo;
+ mOnReadyCallback = onReadyCallback;
+ }
+
+ private void onReady() {
+ long identity = Binder.clearCallingIdentity();
+ try {
+ mOnReadyCallback.onReady();
+ } finally {
+ Binder.restoreCallingIdentity(identity);
+ }
+ }
+
+ @Override
+ public void onServiceConnected(ComponentName name, IBinder service) {
+ final ISyncAdapter adapter = ISyncAdapter.Stub.asInterface(service);
+
+ try {
+ adapter.onUnsyncableAccount(new ISyncAdapterUnsyncableAccountCallback.Stub() {
+ @Override
+ public void onUnsyncableAccountDone(boolean isReady) {
+ if (isReady) {
+ onReady();
+ }
+ }
+ });
+ } catch (RemoteException e) {
+ Slog.e(TAG, "Could not call onUnsyncableAccountDone " + mSyncAdapterInfo, e);
+ /*
+ * The default implementation of adapter.onUnsyncableAccount returns true. Hence if
+ * there is a crash in the implementation, assume the default behavior.
+ */
+ onReady();
+ }
+ }
+
+ @Override
+ public void onServiceDisconnected(ComponentName name) {
+ // Wait until the service connects again
+ }
+ }
+
/**
* A helper object to keep track of the time we have spent syncing since the last boot
*/
@@ -3199,7 +3313,7 @@
return SYNC_OP_STATE_INVALID;
}
// Drop this sync request if it isn't syncable.
- state = computeSyncable(target.account, target.userId, target.provider);
+ state = computeSyncable(target.account, target.userId, target.provider, true);
if (state == AuthorityInfo.SYNCABLE_NO_ACCOUNT_ACCESS) {
if (isLoggable) {
Slog.v(TAG, " Dropping sync operation: "
diff --git a/services/core/java/com/android/server/job/JobStore.java b/services/core/java/com/android/server/job/JobStore.java
index 6da783c..a24a4ac 100644
--- a/services/core/java/com/android/server/job/JobStore.java
+++ b/services/core/java/com/android/server/job/JobStore.java
@@ -1052,13 +1052,18 @@
final ArraySet<JobStatus> jobs = mJobs.get(uid);
final int sourceUid = job.getSourceUid();
final ArraySet<JobStatus> jobsForSourceUid = mJobsPerSourceUid.get(sourceUid);
- boolean didRemove = jobs != null && jobs.remove(job) && jobsForSourceUid.remove(job);
- if (didRemove) {
- if (jobs.size() == 0) {
- // no more jobs for this uid; let the now-empty set object be GC'd.
+ final boolean didRemove = jobs != null && jobs.remove(job);
+ final boolean sourceRemove = jobsForSourceUid != null && jobsForSourceUid.remove(job);
+ if (didRemove != sourceRemove) {
+ Slog.wtf(TAG, "Job presence mismatch; caller=" + didRemove
+ + " source=" + sourceRemove);
+ }
+ if (didRemove || sourceRemove) {
+ // no more jobs for this uid? let the now-empty set objects be GC'd.
+ if (jobs != null && jobs.size() == 0) {
mJobs.remove(uid);
}
- if (jobsForSourceUid.size() == 0) {
+ if (jobsForSourceUid != null && jobsForSourceUid.size() == 0) {
mJobsPerSourceUid.remove(sourceUid);
}
return true;
diff --git a/services/core/java/com/android/server/location/GnssLocationProvider.java b/services/core/java/com/android/server/location/GnssLocationProvider.java
index 48d275c..55c0f5a 100644
--- a/services/core/java/com/android/server/location/GnssLocationProvider.java
+++ b/services/core/java/com/android/server/location/GnssLocationProvider.java
@@ -64,6 +64,7 @@
import android.os.SystemProperties;
import android.os.UserHandle;
import android.os.WorkSource;
+import android.os.WorkSource.WorkChain;
import android.provider.Settings;
import android.provider.Telephony.Carriers;
import android.provider.Telephony.Sms.Intents;
@@ -346,7 +347,8 @@
// Current request from underlying location clients.
private ProviderRequest mProviderRequest = null;
- // Current list of underlying location clients.
+ // The WorkSource associated with the most recent client request (i.e, most recent call to
+ // setRequest).
private WorkSource mWorkSource = null;
// True if gps should be disabled (used to support battery saver mode in settings).
private boolean mDisableGps = false;
@@ -408,6 +410,7 @@
private final IAppOpsService mAppOpsService;
private final IBatteryStats mBatteryStats;
+ // Current list of underlying location clients.
// only modified on handler thread
private WorkSource mClientSource = new WorkSource();
@@ -1345,46 +1348,80 @@
}
private void updateClientUids(WorkSource source) {
- // Update work source.
- WorkSource[] changes = mClientSource.setReturningDiffs(source);
- if (changes == null) {
+ if (source.equals(mClientSource)) {
return;
}
- WorkSource newWork = changes[0];
- WorkSource goneWork = changes[1];
- // Update sources that were not previously tracked.
- if (newWork != null) {
- int lastuid = -1;
- for (int i = 0; i < newWork.size(); i++) {
- try {
- int uid = newWork.get(i);
- mAppOpsService.startOperation(AppOpsManager.getToken(mAppOpsService),
- AppOpsManager.OP_GPS, uid, newWork.getName(i));
- if (uid != lastuid) {
- lastuid = uid;
- mBatteryStats.noteStartGps(uid);
- }
- } catch (RemoteException e) {
- Log.w(TAG, "RemoteException", e);
- }
- }
+ // (1) Inform BatteryStats that the list of IDs we're tracking changed.
+ try {
+ mBatteryStats.noteGpsChanged(mClientSource, source);
+ } catch (RemoteException e) {
+ Log.w(TAG, "RemoteException", e);
}
- // Update sources that are no longer tracked.
- if (goneWork != null) {
- int lastuid = -1;
- for (int i = 0; i < goneWork.size(); i++) {
- try {
- int uid = goneWork.get(i);
- mAppOpsService.finishOperation(AppOpsManager.getToken(mAppOpsService),
- AppOpsManager.OP_GPS, uid, goneWork.getName(i));
- if (uid != lastuid) {
- lastuid = uid;
- mBatteryStats.noteStopGps(uid);
+ // (2) Inform AppOps service about the list of changes to UIDs.
+
+ List<WorkChain>[] diffs = WorkSource.diffChains(mClientSource, source);
+ if (diffs != null) {
+ List<WorkChain> newChains = diffs[0];
+ List<WorkChain> goneChains = diffs[1];
+
+ if (newChains != null) {
+ for (int i = 0; i < newChains.size(); ++i) {
+ final WorkChain newChain = newChains.get(i);
+ try {
+ mAppOpsService.startOperation(AppOpsManager.getToken(mAppOpsService),
+ AppOpsManager.OP_GPS, newChain.getAttributionUid(),
+ newChain.getAttributionTag());
+ } catch (RemoteException e) {
+ Log.w(TAG, "RemoteException", e);
}
- } catch (RemoteException e) {
- Log.w(TAG, "RemoteException", e);
+ }
+ }
+
+ if (goneChains != null) {
+ for (int i = 0; i < goneChains.size(); i++) {
+ final WorkChain goneChain = goneChains.get(i);
+ try {
+ mAppOpsService.finishOperation(AppOpsManager.getToken(mAppOpsService),
+ AppOpsManager.OP_GPS, goneChain.getAttributionUid(),
+ goneChain.getAttributionTag());
+ } catch (RemoteException e) {
+ Log.w(TAG, "RemoteException", e);
+ }
+ }
+ }
+
+ mClientSource.transferWorkChains(source);
+ }
+
+ // Update the flat UIDs and names list and inform app-ops of all changes.
+ WorkSource[] changes = mClientSource.setReturningDiffs(source);
+ if (changes != null) {
+ WorkSource newWork = changes[0];
+ WorkSource goneWork = changes[1];
+
+ // Update sources that were not previously tracked.
+ if (newWork != null) {
+ for (int i = 0; i < newWork.size(); i++) {
+ try {
+ mAppOpsService.startOperation(AppOpsManager.getToken(mAppOpsService),
+ AppOpsManager.OP_GPS, newWork.get(i), newWork.getName(i));
+ } catch (RemoteException e) {
+ Log.w(TAG, "RemoteException", e);
+ }
+ }
+ }
+
+ // Update sources that are no longer tracked.
+ if (goneWork != null) {
+ for (int i = 0; i < goneWork.size(); i++) {
+ try {
+ mAppOpsService.finishOperation(AppOpsManager.getToken(mAppOpsService),
+ AppOpsManager.OP_GPS, goneWork.get(i), goneWork.getName(i));
+ } catch (RemoteException e) {
+ Log.w(TAG, "RemoteException", e);
+ }
}
}
}
diff --git a/services/core/java/com/android/server/media/MediaSession2Record.java b/services/core/java/com/android/server/media/MediaSession2Record.java
index 824b148..4000a11 100644
--- a/services/core/java/com/android/server/media/MediaSession2Record.java
+++ b/services/core/java/com/android/server/media/MediaSession2Record.java
@@ -137,7 +137,7 @@
final MediaController2 createMediaController(SessionToken2 token) {
mControllerCallback = new ControllerCallback();
- return new MediaController2(mContext, token, mControllerCallback, mMainExecutor);
+ return new MediaController2(mContext, token, mMainExecutor, mControllerCallback);
}
/**
diff --git a/services/core/java/com/android/server/pm/Installer.java b/services/core/java/com/android/server/pm/Installer.java
index c04cdf6..c3f20af 100644
--- a/services/core/java/com/android/server/pm/Installer.java
+++ b/services/core/java/com/android/server/pm/Installer.java
@@ -17,6 +17,7 @@
package com.android.server.pm;
import android.annotation.AppIdInt;
+import android.annotation.NonNull;
import android.annotation.Nullable;
import android.annotation.UserIdInt;
import android.content.Context;
@@ -288,43 +289,44 @@
public void dexopt(String apkPath, int uid, @Nullable String pkgName, String instructionSet,
int dexoptNeeded, @Nullable String outputPath, int dexFlags,
String compilerFilter, @Nullable String volumeUuid, @Nullable String sharedLibraries,
- @Nullable String seInfo, boolean downgrade, int targetSdkVersion)
- throws InstallerException {
+ @Nullable String seInfo, boolean downgrade, int targetSdkVersion,
+ @Nullable String profileName) throws InstallerException {
assertValidInstructionSet(instructionSet);
if (!checkBeforeRemote()) return;
try {
mInstalld.dexopt(apkPath, uid, pkgName, instructionSet, dexoptNeeded, outputPath,
dexFlags, compilerFilter, volumeUuid, sharedLibraries, seInfo, downgrade,
- targetSdkVersion);
+ targetSdkVersion, profileName);
} catch (Exception e) {
throw InstallerException.from(e);
}
}
- public boolean mergeProfiles(int uid, String packageName) throws InstallerException {
- if (!checkBeforeRemote()) return false;
- try {
- return mInstalld.mergeProfiles(uid, packageName);
- } catch (Exception e) {
- throw InstallerException.from(e);
- }
- }
-
- public boolean dumpProfiles(int uid, String packageName, String codePaths)
+ public boolean mergeProfiles(int uid, String packageName, String profileName)
throws InstallerException {
if (!checkBeforeRemote()) return false;
try {
- return mInstalld.dumpProfiles(uid, packageName, codePaths);
+ return mInstalld.mergeProfiles(uid, packageName, profileName);
} catch (Exception e) {
throw InstallerException.from(e);
}
}
- public boolean copySystemProfile(String systemProfile, int uid, String packageName)
+ public boolean dumpProfiles(int uid, String packageName, String profileName, String codePath)
throws InstallerException {
if (!checkBeforeRemote()) return false;
try {
- return mInstalld.copySystemProfile(systemProfile, uid, packageName);
+ return mInstalld.dumpProfiles(uid, packageName, profileName, codePath);
+ } catch (Exception e) {
+ throw InstallerException.from(e);
+ }
+ }
+
+ public boolean copySystemProfile(String systemProfile, int uid, String packageName,
+ String profileName) throws InstallerException {
+ if (!checkBeforeRemote()) return false;
+ try {
+ return mInstalld.copySystemProfile(systemProfile, uid, packageName, profileName);
} catch (Exception e) {
throw InstallerException.from(e);
}
@@ -368,10 +370,10 @@
}
}
- public void clearAppProfiles(String packageName) throws InstallerException {
+ public void clearAppProfiles(String packageName, String profileName) throws InstallerException {
if (!checkBeforeRemote()) return;
try {
- mInstalld.clearAppProfiles(packageName);
+ mInstalld.clearAppProfiles(packageName, profileName);
} catch (Exception e) {
throw InstallerException.from(e);
}
@@ -490,6 +492,16 @@
}
}
+ public void assertFsverityRootHashMatches(String filePath, @NonNull byte[] expectedHash)
+ throws InstallerException {
+ if (!checkBeforeRemote()) return;
+ try {
+ mInstalld.assertFsverityRootHashMatches(filePath, expectedHash);
+ } catch (Exception e) {
+ throw InstallerException.from(e);
+ }
+ }
+
public boolean reconcileSecondaryDexFile(String apkPath, String packageName, int uid,
String[] isas, @Nullable String volumeUuid, int flags) throws InstallerException {
for (int i = 0; i < isas.length; i++) {
@@ -514,21 +526,21 @@
}
}
- public boolean createProfileSnapshot(int appId, String packageName, String codePath)
- throws InstallerException {
+ public boolean createProfileSnapshot(int appId, String packageName, String profileName,
+ String classpath) throws InstallerException {
if (!checkBeforeRemote()) return false;
try {
- return mInstalld.createProfileSnapshot(appId, packageName, codePath);
+ return mInstalld.createProfileSnapshot(appId, packageName, profileName, classpath);
} catch (Exception e) {
throw InstallerException.from(e);
}
}
- public void destroyProfileSnapshot(String packageName, String codePath)
+ public void destroyProfileSnapshot(String packageName, String profileName)
throws InstallerException {
if (!checkBeforeRemote()) return;
try {
- mInstalld.destroyProfileSnapshot(packageName, codePath);
+ mInstalld.destroyProfileSnapshot(packageName, profileName);
} catch (Exception e) {
throw InstallerException.from(e);
}
diff --git a/services/core/java/com/android/server/pm/OtaDexoptService.java b/services/core/java/com/android/server/pm/OtaDexoptService.java
index 0395011..5bf38dc 100644
--- a/services/core/java/com/android/server/pm/OtaDexoptService.java
+++ b/services/core/java/com/android/server/pm/OtaDexoptService.java
@@ -261,12 +261,12 @@
String instructionSet, int dexoptNeeded, @Nullable String outputPath,
int dexFlags, String compilerFilter, @Nullable String volumeUuid,
@Nullable String sharedLibraries, @Nullable String seInfo, boolean downgrade,
- int targetSdkVersion)
+ int targetSdkVersion, @Nullable String profileName)
throws InstallerException {
final StringBuilder builder = new StringBuilder();
- // The version. Right now it's 4.
- builder.append("4 ");
+ // The version. Right now it's 5.
+ builder.append("5 ");
builder.append("dexopt");
@@ -283,6 +283,7 @@
encodeParameter(builder, seInfo);
encodeParameter(builder, downgrade);
encodeParameter(builder, targetSdkVersion);
+ encodeParameter(builder, profileName);
commands.add(builder.toString());
}
diff --git a/services/core/java/com/android/server/pm/PackageDexOptimizer.java b/services/core/java/com/android/server/pm/PackageDexOptimizer.java
index 324dc5f..cde8cb7 100644
--- a/services/core/java/com/android/server/pm/PackageDexOptimizer.java
+++ b/services/core/java/com/android/server/pm/PackageDexOptimizer.java
@@ -20,6 +20,7 @@
import android.content.Context;
import android.content.pm.ApplicationInfo;
import android.content.pm.PackageParser;
+import android.content.pm.dex.ArtManager;
import android.os.FileUtils;
import android.os.PowerManager;
import android.os.SystemClock;
@@ -206,12 +207,14 @@
}
}
+ String profileName = ArtManager.getProfileName(i == 0 ? null : pkg.splitNames[i - 1]);
+
final boolean isUsedByOtherApps = options.isDexoptAsSharedLibrary()
|| packageUseInfo.isUsedByOtherApps(path);
final String compilerFilter = getRealCompilerFilter(pkg.applicationInfo,
options.getCompilerFilter(), isUsedByOtherApps);
final boolean profileUpdated = options.isCheckForProfileUpdates() &&
- isProfileUpdated(pkg, sharedGid, compilerFilter);
+ isProfileUpdated(pkg, sharedGid, profileName, compilerFilter);
// Get the dexopt flags after getRealCompilerFilter to make sure we get the correct
// flags.
@@ -220,7 +223,7 @@
for (String dexCodeIsa : dexCodeInstructionSets) {
int newResult = dexOptPath(pkg, path, dexCodeIsa, compilerFilter,
profileUpdated, classLoaderContexts[i], dexoptFlags, sharedGid,
- packageStats, options.isDowngrade());
+ packageStats, options.isDowngrade(), profileName);
// The end result is:
// - FAILED if any path failed,
// - PERFORMED if at least one path needed compilation,
@@ -244,7 +247,8 @@
@GuardedBy("mInstallLock")
private int dexOptPath(PackageParser.Package pkg, String path, String isa,
String compilerFilter, boolean profileUpdated, String classLoaderContext,
- int dexoptFlags, int uid, CompilerStats.PackageStats packageStats, boolean downgrade) {
+ int dexoptFlags, int uid, CompilerStats.PackageStats packageStats, boolean downgrade,
+ String profileName) {
int dexoptNeeded = getDexoptNeeded(path, isa, compilerFilter, classLoaderContext,
profileUpdated, downgrade);
if (Math.abs(dexoptNeeded) == DexFile.NO_DEXOPT_NEEDED) {
@@ -270,7 +274,8 @@
// primary dex files.
mInstaller.dexopt(path, uid, pkg.packageName, isa, dexoptNeeded, oatDir, dexoptFlags,
compilerFilter, pkg.volumeUuid, classLoaderContext, pkg.applicationInfo.seInfo,
- false /* downgrade*/, pkg.applicationInfo.targetSdkVersion);
+ false /* downgrade*/, pkg.applicationInfo.targetSdkVersion,
+ profileName);
if (packageStats != null) {
long endTime = System.currentTimeMillis();
@@ -391,7 +396,7 @@
mInstaller.dexopt(path, info.uid, info.packageName, isa, /*dexoptNeeded*/ 0,
/*oatDir*/ null, dexoptFlags,
compilerFilter, info.volumeUuid, classLoaderContext, info.seInfoUser,
- options.isDowngrade(), info.targetSdkVersion);
+ options.isDowngrade(), info.targetSdkVersion, /*profileName*/ null);
}
return DEX_OPT_PERFORMED;
@@ -550,14 +555,15 @@
* current profile and the reference profile will be merged and subsequent calls
* may return a different result.
*/
- private boolean isProfileUpdated(PackageParser.Package pkg, int uid, String compilerFilter) {
+ private boolean isProfileUpdated(PackageParser.Package pkg, int uid, String profileName,
+ String compilerFilter) {
// Check if we are allowed to merge and if the compiler filter is profile guided.
if (!isProfileGuidedCompilerFilter(compilerFilter)) {
return false;
}
// Merge profiles. It returns whether or not there was an updated in the profile info.
try {
- return mInstaller.mergeProfiles(uid, pkg.packageName);
+ return mInstaller.mergeProfiles(uid, pkg.packageName, profileName);
} catch (InstallerException e) {
Slog.w(TAG, "Failed to merge profiles", e);
}
diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java
index 5dfd3ae..837a118 100644
--- a/services/core/java/com/android/server/pm/PackageManagerService.java
+++ b/services/core/java/com/android/server/pm/PackageManagerService.java
@@ -193,6 +193,7 @@
import android.content.pm.VerifierDeviceIdentity;
import android.content.pm.VerifierInfo;
import android.content.pm.VersionedPackage;
+import android.content.pm.dex.ArtManager;
import android.content.pm.dex.DexMetadataHelper;
import android.content.pm.dex.IArtManager;
import android.content.res.Resources;
@@ -337,6 +338,7 @@
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.nio.charset.StandardCharsets;
+import java.security.DigestException;
import java.security.DigestInputStream;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
@@ -8291,11 +8293,13 @@
}
private void collectCertificatesLI(PackageSetting ps, PackageParser.Package pkg,
- final @ParseFlags int parseFlags, boolean forceCollect) throws PackageManagerException {
+ boolean forceCollect) throws PackageManagerException {
// When upgrading from pre-N MR1, verify the package time stamp using the package
// directory and not the APK file.
final long lastModifiedTime = mIsPreNMR1Upgrade
? new File(pkg.codePath).lastModified() : getLastModifiedTime(pkg);
+ // Note that currently skipVerify skips verification on both base and splits for simplicity.
+ final boolean skipVerify = forceCollect && canSkipFullPackageVerification(pkg);
if (ps != null && !forceCollect
&& ps.codePathString.equals(pkg.codePath)
&& ps.timeStamp == lastModifiedTime
@@ -8321,7 +8325,7 @@
try {
Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "collectCertificates");
- PackageParser.collectCertificates(pkg, parseFlags);
+ PackageParser.collectCertificates(pkg, skipVerify);
} catch (PackageParserException e) {
throw PackageManagerException.from(e);
} finally {
@@ -8415,6 +8419,48 @@
return scannedPkg;
}
+ /**
+ * Returns if full apk verification can be skipped for the whole package, including the splits.
+ */
+ private boolean canSkipFullPackageVerification(PackageParser.Package pkg) {
+ if (!canSkipFullApkVerification(pkg.baseCodePath)) {
+ return false;
+ }
+ // TODO: Allow base and splits to be verified individually.
+ if (!ArrayUtils.isEmpty(pkg.splitCodePaths)) {
+ for (int i = 0; i < pkg.splitCodePaths.length; i++) {
+ if (!canSkipFullApkVerification(pkg.splitCodePaths[i])) {
+ return false;
+ }
+ }
+ }
+ return true;
+ }
+
+ /**
+ * Returns if full apk verification can be skipped, depending on current FSVerity setup and
+ * whether the apk contains signed root hash. Note that the signer's certificate still needs to
+ * match one in a trusted source, and should be done separately.
+ */
+ private boolean canSkipFullApkVerification(String apkPath) {
+ byte[] rootHashObserved = null;
+ try {
+ rootHashObserved = VerityUtils.generateFsverityRootHash(apkPath);
+ if (rootHashObserved == null) {
+ return false; // APK does not contain Merkle tree root hash.
+ }
+ synchronized (mInstallLock) {
+ // Returns whether the observed root hash matches what kernel has.
+ mInstaller.assertFsverityRootHashMatches(apkPath, rootHashObserved);
+ return true;
+ }
+ } catch (InstallerException | IOException | DigestException |
+ NoSuchAlgorithmException e) {
+ Slog.w(TAG, "Error in fsverity check. Fallback to full apk verification.", e);
+ }
+ return false;
+ }
+
// Temporary to catch potential issues with refactoring
private static boolean REFACTOR_DEBUG = true;
/**
@@ -8626,10 +8672,11 @@
}
// Verify certificates against what was last scanned. If it is an updated priv app, we will
- // force the verification. Full apk verification will happen unless apk verity is set up for
- // the file. In that case, only small part of the apk is verified upfront.
- collectCertificatesLI(pkgSetting, pkg, parseFlags,
- PackageManagerServiceUtils.isApkVerificationForced(disabledPkgSetting));
+ // force re-collecting certificate. Full apk verification will happen unless apk verity is
+ // set up for the file. In that case, only small part of the apk is verified upfront.
+ final boolean forceCollect = PackageManagerServiceUtils.isApkVerificationForced(
+ disabledPkgSetting);
+ collectCertificatesLI(pkgSetting, pkg, forceCollect);
boolean shouldHideSystemApp = false;
// A new application appeared on /system, but, we already have a copy of
@@ -8870,7 +8917,8 @@
// PackageDexOptimizer to prevent this happening on first boot. The issue
// is that we don't have a good way to say "do this only once".
if (!mInstaller.copySystemProfile(profileFile.getAbsolutePath(),
- pkg.applicationInfo.uid, pkg.packageName)) {
+ pkg.applicationInfo.uid, pkg.packageName,
+ ArtManager.getProfileName(null))) {
Log.e(TAG, "Installer failed to copy system profile!");
} else {
// Disabled as this causes speed-profile compilation during first boot
@@ -8905,7 +8953,8 @@
// issue is that we don't have a good way to say "do this only
// once".
if (!mInstaller.copySystemProfile(profileFile.getAbsolutePath(),
- pkg.applicationInfo.uid, pkg.packageName)) {
+ pkg.applicationInfo.uid, pkg.packageName,
+ ArtManager.getProfileName(null))) {
Log.e(TAG, "Failed to copy system profile for stub package!");
} else {
useProfileForDexopt = true;
@@ -9330,14 +9379,7 @@
synchronized (mInstallLock) {
Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "dump profiles");
- final int sharedGid = UserHandle.getSharedAppGid(pkg.applicationInfo.uid);
- try {
- List<String> allCodePaths = pkg.getAllCodePathsExcludingResourceOnly();
- String codePaths = TextUtils.join(";", allCodePaths);
- mInstaller.dumpProfiles(sharedGid, packageName, codePaths);
- } catch (InstallerException e) {
- Slog.w(TAG, "Failed to dump profiles", e);
- }
+ mArtManagerService.dumpProfiles(pkg);
Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
}
}
@@ -9413,6 +9455,8 @@
for (int i = 0; i < childCount; i++) {
clearAppDataLeafLIF(pkg.childPackages.get(i), userId, flags);
}
+
+ clearAppProfilesLIF(pkg, UserHandle.USER_ALL);
}
private void clearAppDataLeafLIF(PackageParser.Package pkg, int userId, int flags) {
@@ -9485,18 +9529,10 @@
Slog.wtf(TAG, "Package was null!", new Throwable());
return;
}
- clearAppProfilesLeafLIF(pkg);
+ mArtManagerService.clearAppProfiles(pkg);
final int childCount = (pkg.childPackages != null) ? pkg.childPackages.size() : 0;
for (int i = 0; i < childCount; i++) {
- clearAppProfilesLeafLIF(pkg.childPackages.get(i));
- }
- }
-
- private void clearAppProfilesLeafLIF(PackageParser.Package pkg) {
- try {
- mInstaller.clearAppProfiles(pkg.packageName);
- } catch (InstallerException e) {
- Slog.w(TAG, String.valueOf(e));
+ mArtManagerService.clearAppProfiles(pkg.childPackages.get(i));
}
}
@@ -16156,7 +16192,6 @@
clearAppDataLIF(pkg, UserHandle.USER_ALL, StorageManager.FLAG_STORAGE_DE
| StorageManager.FLAG_STORAGE_CE | Installer.FLAG_CLEAR_CODE_CACHE_ONLY);
- clearAppProfilesLIF(deletedPackage, UserHandle.USER_ALL);
try {
final PackageParser.Package newPackage = scanPackageTracedLI(pkg, parseFlags,
@@ -16295,7 +16330,6 @@
// Successfully disabled the old package. Now proceed with re-installation
clearAppDataLIF(pkg, UserHandle.USER_ALL, StorageManager.FLAG_STORAGE_DE
| StorageManager.FLAG_STORAGE_CE | Installer.FLAG_CLEAR_CODE_CACHE_ONLY);
- clearAppProfilesLIF(deletedPackage, UserHandle.USER_ALL);
res.setReturnCode(PackageManager.INSTALL_SUCCEEDED);
pkg.setApplicationInfoFlags(ApplicationInfo.FLAG_UPDATED_SYSTEM_APP,
@@ -16755,7 +16789,7 @@
if (args.signingDetails != PackageParser.SigningDetails.UNKNOWN) {
pkg.setSigningDetails(args.signingDetails);
} else {
- PackageParser.collectCertificates(pkg, parseFlags);
+ PackageParser.collectCertificates(pkg, false /* skipVerify */);
}
} catch (PackageParserException e) {
res.setError("Failed collect during installPackageLI", e);
@@ -20368,7 +20402,6 @@
}
clearAppDataLIF(pkg, UserHandle.USER_ALL, FLAG_STORAGE_DE
| FLAG_STORAGE_CE | Installer.FLAG_CLEAR_CODE_CACHE_ONLY);
- clearAppProfilesLIF(pkg, UserHandle.USER_ALL);
mDexManager.notifyPackageUpdated(pkg.packageName,
pkg.baseCodePath, pkg.splitCodePaths);
}
diff --git a/services/core/java/com/android/server/pm/PackageManagerServiceUtils.java b/services/core/java/com/android/server/pm/PackageManagerServiceUtils.java
index bf3eb8e..76c199b 100644
--- a/services/core/java/com/android/server/pm/PackageManagerServiceUtils.java
+++ b/services/core/java/com/android/server/pm/PackageManagerServiceUtils.java
@@ -562,8 +562,7 @@
private static boolean matchSignatureInSystem(PackageSetting pkgSetting,
PackageSetting disabledPkgSetting) {
try {
- PackageParser.collectCertificates(disabledPkgSetting.pkg,
- PackageParser.PARSE_IS_SYSTEM_DIR);
+ PackageParser.collectCertificates(disabledPkgSetting.pkg, true /* skipVerify */);
if (compareSignatures(pkgSetting.signatures.mSigningDetails.signatures,
disabledPkgSetting.signatures.mSigningDetails.signatures)
!= PackageManager.SIGNATURE_MATCH) {
diff --git a/services/core/java/com/android/server/pm/dex/ArtManagerService.java b/services/core/java/com/android/server/pm/dex/ArtManagerService.java
index 8178689..e290272 100644
--- a/services/core/java/com/android/server/pm/dex/ArtManagerService.java
+++ b/services/core/java/com/android/server/pm/dex/ArtManagerService.java
@@ -23,9 +23,10 @@
import android.content.pm.PackageManager;
import android.content.pm.PackageParser;
import android.content.pm.dex.ArtManager;
+import android.content.pm.dex.ArtManager.ProfileType;
import android.content.pm.dex.DexMetadataHelper;
import android.os.Binder;
-import android.os.Environment;
+import android.os.Build;
import android.os.Handler;
import android.os.ParcelFileDescriptor;
import android.os.RemoteException;
@@ -33,6 +34,7 @@
import android.content.pm.dex.ISnapshotRuntimeProfileCallback;
import android.os.SystemProperties;
import android.os.UserHandle;
+import android.system.Os;
import android.util.ArrayMap;
import android.util.Slog;
@@ -44,6 +46,9 @@
import com.android.server.pm.Installer.InstallerException;
import java.io.File;
import java.io.FileNotFoundException;
+import libcore.io.IoUtils;
+import libcore.util.NonNull;
+import libcore.util.Nullable;
/**
* A system service that provides access to runtime and compiler artifacts.
@@ -63,6 +68,12 @@
private static boolean DEBUG = false;
private static boolean DEBUG_IGNORE_PERMISSIONS = false;
+ // Package name used to create the profile directory layout when
+ // taking a snapshot of the boot image profile.
+ private static final String BOOT_IMAGE_ANDROID_PACKAGE = "android";
+ // Profile name used for the boot image profile.
+ private static final String BOOT_IMAGE_PROFILE_NAME = "android.prof";
+
private final IPackageManager mPackageManager;
private final Object mInstallLock;
@GuardedBy("mInstallLock")
@@ -78,20 +89,36 @@
}
@Override
- public void snapshotRuntimeProfile(String packageName, String codePath,
- ISnapshotRuntimeProfileCallback callback) {
+ public void snapshotRuntimeProfile(@ProfileType int profileType, @Nullable String packageName,
+ @Nullable String codePath, @NonNull ISnapshotRuntimeProfileCallback callback) {
// Sanity checks on the arguments.
- Preconditions.checkStringNotEmpty(packageName);
- Preconditions.checkStringNotEmpty(codePath);
Preconditions.checkNotNull(callback);
- // Verify that the caller has the right permissions.
- checkReadRuntimeProfilePermission();
+ boolean bootImageProfile = profileType == ArtManager.PROFILE_BOOT_IMAGE;
+ if (!bootImageProfile) {
+ Preconditions.checkStringNotEmpty(codePath);
+ Preconditions.checkStringNotEmpty(packageName);
+ }
+
+ // Verify that the caller has the right permissions and that the runtime profiling is
+ // enabled. The call to isRuntimePermissions will checkReadRuntimeProfilePermission.
+ if (!isRuntimeProfilingEnabled(profileType)) {
+ throw new IllegalStateException("Runtime profiling is not enabled for " + profileType);
+ }
if (DEBUG) {
Slog.d(TAG, "Requested snapshot for " + packageName + ":" + codePath);
}
+ if (bootImageProfile) {
+ snapshotBootImageProfile(callback);
+ } else {
+ snapshotAppProfile(packageName, codePath, callback);
+ }
+ }
+
+ private void snapshotAppProfile(String packageName, String codePath,
+ ISnapshotRuntimeProfileCallback callback) {
PackageInfo info = null;
try {
// Note that we use the default user 0 to retrieve the package info.
@@ -111,11 +138,13 @@
}
boolean pathFound = info.applicationInfo.getBaseCodePath().equals(codePath);
+ String splitName = null;
String[] splitCodePaths = info.applicationInfo.getSplitCodePaths();
if (!pathFound && (splitCodePaths != null)) {
- for (String path : splitCodePaths) {
- if (path.equals(codePath)) {
+ for (int i = splitCodePaths.length - 1; i >= 0; i--) {
+ if (splitCodePaths[i].equals(codePath)) {
pathFound = true;
+ splitName = info.applicationInfo.splitNames[i];
break;
}
}
@@ -126,18 +155,25 @@
}
// All good, create the profile snapshot.
- createProfileSnapshot(packageName, codePath, callback, info);
+ int appId = UserHandle.getAppId(info.applicationInfo.uid);
+ if (appId < 0) {
+ postError(callback, packageName, ArtManager.SNAPSHOT_FAILED_INTERNAL_ERROR);
+ Slog.wtf(TAG, "AppId is -1 for package: " + packageName);
+ return;
+ }
+
+ createProfileSnapshot(packageName, ArtManager.getProfileName(splitName), codePath,
+ appId, callback);
// Destroy the snapshot, we no longer need it.
- destroyProfileSnapshot(packageName, codePath);
+ destroyProfileSnapshot(packageName, ArtManager.getProfileName(splitName));
}
- private void createProfileSnapshot(String packageName, String codePath,
- ISnapshotRuntimeProfileCallback callback, PackageInfo info) {
+ private void createProfileSnapshot(String packageName, String profileName, String classpath,
+ int appId, ISnapshotRuntimeProfileCallback callback) {
// Ask the installer to snapshot the profile.
synchronized (mInstallLock) {
try {
- if (!mInstaller.createProfileSnapshot(UserHandle.getAppId(info.applicationInfo.uid),
- packageName, codePath)) {
+ if (!mInstaller.createProfileSnapshot(appId, packageName, profileName, classpath)) {
postError(callback, packageName, ArtManager.SNAPSHOT_FAILED_INTERNAL_ERROR);
return;
}
@@ -148,38 +184,64 @@
}
// Open the snapshot and invoke the callback.
- File snapshotProfile = Environment.getProfileSnapshotPath(packageName, codePath);
- ParcelFileDescriptor fd;
+ File snapshotProfile = ArtManager.getProfileSnapshotFileForName(packageName, profileName);
+
+ ParcelFileDescriptor fd = null;
try {
fd = ParcelFileDescriptor.open(snapshotProfile, ParcelFileDescriptor.MODE_READ_ONLY);
postSuccess(packageName, fd, callback);
} catch (FileNotFoundException e) {
- Slog.w(TAG, "Could not open snapshot profile for " + packageName + ":" + codePath, e);
+ Slog.w(TAG, "Could not open snapshot profile for " + packageName + ":"
+ + snapshotProfile, e);
postError(callback, packageName, ArtManager.SNAPSHOT_FAILED_INTERNAL_ERROR);
+ } finally {
+ IoUtils.closeQuietly(fd);
}
}
- private void destroyProfileSnapshot(String packageName, String codePath) {
+ private void destroyProfileSnapshot(String packageName, String profileName) {
if (DEBUG) {
- Slog.d(TAG, "Destroying profile snapshot for" + packageName + ":" + codePath);
+ Slog.d(TAG, "Destroying profile snapshot for" + packageName + ":" + profileName);
}
synchronized (mInstallLock) {
try {
- mInstaller.destroyProfileSnapshot(packageName, codePath);
+ mInstaller.destroyProfileSnapshot(packageName, profileName);
} catch (InstallerException e) {
Slog.e(TAG, "Failed to destroy profile snapshot for " +
- packageName + ":" + codePath, e);
+ packageName + ":" + profileName, e);
}
}
}
@Override
- public boolean isRuntimeProfilingEnabled() {
+ public boolean isRuntimeProfilingEnabled(@ProfileType int profileType) {
// Verify that the caller has the right permissions.
checkReadRuntimeProfilePermission();
- return SystemProperties.getBoolean("dalvik.vm.usejitprofiles", false);
+ switch (profileType) {
+ case ArtManager.PROFILE_APPS :
+ return SystemProperties.getBoolean("dalvik.vm.usejitprofiles", false);
+ case ArtManager.PROFILE_BOOT_IMAGE:
+ return (Build.IS_USERDEBUG || Build.IS_ENG) &&
+ SystemProperties.getBoolean("dalvik.vm.usejitprofiles", false) &&
+ SystemProperties.getBoolean("dalvik.vm.profilebootimage", false);
+ default:
+ throw new IllegalArgumentException("Invalid profile type:" + profileType);
+ }
+ }
+
+ private void snapshotBootImageProfile(ISnapshotRuntimeProfileCallback callback) {
+ // Combine the profiles for boot classpath and system server classpath.
+ // This avoids having yet another type of profiles and simplifies the processing.
+ String classpath = String.join(":", Os.getenv("BOOTCLASSPATH"),
+ Os.getenv("SYSTEMSERVERCLASSPATH"));
+
+ // Create the snapshot.
+ createProfileSnapshot(BOOT_IMAGE_ANDROID_PACKAGE, BOOT_IMAGE_PROFILE_NAME, classpath,
+ /*appId*/ -1, callback);
+ // Destroy the snapshot, we no longer need it.
+ destroyProfileSnapshot(BOOT_IMAGE_ANDROID_PACKAGE, BOOT_IMAGE_PROFILE_NAME);
}
/**
@@ -284,6 +346,40 @@
}
/**
+ * Clear the profiles for the given package.
+ */
+ public void clearAppProfiles(PackageParser.Package pkg) {
+ try {
+ ArrayMap<String, String> packageProfileNames = getPackageProfileNames(pkg);
+ for (int i = packageProfileNames.size() - 1; i >= 0; i--) {
+ String profileName = packageProfileNames.valueAt(i);
+ mInstaller.clearAppProfiles(pkg.packageName, profileName);
+ }
+ } catch (InstallerException e) {
+ Slog.w(TAG, String.valueOf(e));
+ }
+ }
+
+ /**
+ * Dumps the profiles for the given package.
+ */
+ public void dumpProfiles(PackageParser.Package pkg) {
+ final int sharedGid = UserHandle.getSharedAppGid(pkg.applicationInfo.uid);
+ try {
+ ArrayMap<String, String> packageProfileNames = getPackageProfileNames(pkg);
+ for (int i = packageProfileNames.size() - 1; i >= 0; i--) {
+ String codePath = packageProfileNames.keyAt(i);
+ String profileName = packageProfileNames.valueAt(i);
+ synchronized (mInstallLock) {
+ mInstaller.dumpProfiles(sharedGid, pkg.packageName, profileName, codePath);
+ }
+ }
+ } catch (InstallerException e) {
+ Slog.w(TAG, "Failed to dump profiles", e);
+ }
+ }
+
+ /**
* Build the profiles names for all the package code paths (excluding resource only paths).
* Return the map [code path -> profile name].
*/
diff --git a/services/core/java/com/android/server/power/PowerManagerService.java b/services/core/java/com/android/server/power/PowerManagerService.java
index cf36166..db83158 100644
--- a/services/core/java/com/android/server/power/PowerManagerService.java
+++ b/services/core/java/com/android/server/power/PowerManagerService.java
@@ -3763,12 +3763,8 @@
proto.write(PowerManagerServiceDumpProto.UidStateProto.UID_STRING, UserHandle.formatUid(uid));
proto.write(PowerManagerServiceDumpProto.UidStateProto.IS_ACTIVE, state.mActive);
proto.write(PowerManagerServiceDumpProto.UidStateProto.NUM_WAKE_LOCKS, state.mNumWakeLocks);
- if (state.mProcState == ActivityManager.PROCESS_STATE_UNKNOWN) {
- proto.write(PowerManagerServiceDumpProto.UidStateProto.IS_PROCESS_STATE_UNKNOWN, true);
- } else {
- proto.write(PowerManagerServiceDumpProto.UidStateProto.PROCESS_STATE,
- ActivityManager.processStateAmToProto(state.mProcState));
- }
+ proto.write(PowerManagerServiceDumpProto.UidStateProto.PROCESS_STATE,
+ ActivityManager.processStateAmToProto(state.mProcState));
proto.end(uIDToken);
}
diff --git a/services/core/java/com/android/server/security/VerityUtils.java b/services/core/java/com/android/server/security/VerityUtils.java
index 3908df4..d2d0e60 100644
--- a/services/core/java/com/android/server/security/VerityUtils.java
+++ b/services/core/java/com/android/server/security/VerityUtils.java
@@ -77,6 +77,14 @@
}
/**
+ * {@see ApkSignatureVerifier#generateFsverityRootHash(String)}.
+ */
+ public static byte[] generateFsverityRootHash(@NonNull String apkPath)
+ throws NoSuchAlgorithmException, DigestException, IOException {
+ return ApkSignatureVerifier.generateFsverityRootHash(apkPath);
+ }
+
+ /**
* Returns a {@code SharedMemory} that contains Merkle tree and fsverity headers for the given
* apk, in the form that can immediately be used for fsverity setup.
*/
diff --git a/services/core/java/com/android/server/stats/StatsCompanionService.java b/services/core/java/com/android/server/stats/StatsCompanionService.java
index baea964..faafb39 100644
--- a/services/core/java/com/android/server/stats/StatsCompanionService.java
+++ b/services/core/java/com/android/server/stats/StatsCompanionService.java
@@ -706,6 +706,8 @@
enforceCallingPermission();
if (DEBUG) Slog.d(TAG, "learned that statsdReady");
sayHiToStatsd(); // tell statsd that we're ready too and link to it
+ mContext.sendBroadcast(new Intent(StatsManager.ACTION_STATSD_STARTED),
+ android.Manifest.permission.DUMP);
}
@Override
diff --git a/services/core/java/com/android/server/wm/WindowStateAnimator.java b/services/core/java/com/android/server/wm/WindowStateAnimator.java
index ba5156b..1cfa956 100644
--- a/services/core/java/com/android/server/wm/WindowStateAnimator.java
+++ b/services/core/java/com/android/server/wm/WindowStateAnimator.java
@@ -238,15 +238,6 @@
return mWin.isAnimating();
}
- /**
- * Is this window currently waiting to run an opening animation?
- */
- boolean isWaitingForOpening() {
- return mService.mAppTransition.isTransitionSet()
- && (mWin.mAppToken != null && mWin.mAppToken.isHidden())
- && mService.mOpeningApps.contains(mWin.mAppToken);
- }
-
void cancelExitAnimationForNextAnimationLocked() {
if (DEBUG_ANIM) Slog.d(TAG,
"cancelExitAnimationForNextAnimationLocked: " + mWin);
@@ -1057,17 +1048,6 @@
return;
}
- // Do not change surface properties of opening apps if we are waiting for the
- // transition to be ready. transitionGoodToGo could be not ready even after all
- // opening apps are drawn. It's only waiting on isFetchingAppTransitionsSpecs()
- // to get the animation spec. (For example, go into Recents and immediately open
- // the same app again before the app's surface is destroyed or saved, the surface
- // is always ready in the whole process.) If we go ahead here, the opening app
- // will be shown with the full size before the correct animation spec arrives.
- if (isWaitingForOpening()) {
- return;
- }
-
boolean displayed = false;
computeShownFrameLocked();
diff --git a/services/core/jni/BroadcastRadio/BroadcastRadioService.cpp b/services/core/jni/BroadcastRadio/BroadcastRadioService.cpp
index 9892146..176ae81 100644
--- a/services/core/jni/BroadcastRadio/BroadcastRadioService.cpp
+++ b/services/core/jni/BroadcastRadio/BroadcastRadioService.cpp
@@ -249,6 +249,15 @@
Tuner::assignHalInterfaces(env, tuner, module.radioModule, halTuner);
ALOGD("Opened tuner %p", halTuner.get());
+
+ bool isConnected = true;
+ halTuner->getConfiguration([&](Result result, const BandConfig& config) {
+ if (result == Result::OK) isConnected = config.antennaConnected;
+ });
+ if (!isConnected) {
+ tunerCb->antennaStateChange(false);
+ }
+
return tuner.release();
}
diff --git a/services/core/jni/BroadcastRadio/Tuner.cpp b/services/core/jni/BroadcastRadio/Tuner.cpp
index 42eb873..42c1332 100644
--- a/services/core/jni/BroadcastRadio/Tuner.cpp
+++ b/services/core/jni/BroadcastRadio/Tuner.cpp
@@ -352,39 +352,6 @@
convert::ThrowIfFailed(env, halTuner->cancelAnnouncement());
}
-static jobject nativeGetProgramInformation(JNIEnv *env, jobject obj, jlong nativeContext) {
- ALOGV("%s", __func__);
- lock_guard<mutex> lk(gContextMutex);
- auto& ctx = getNativeContext(nativeContext);
-
- auto halTuner10 = getHalTuner(ctx);
- auto halTuner11 = ctx.mHalTuner11;
- if (halTuner10 == nullptr) return nullptr;
-
- JavaRef<jobject> jInfo;
- Result halResult;
- Return<void> hidlResult;
- if (halTuner11 != nullptr) {
- hidlResult = halTuner11->getProgramInformation_1_1([&](Result result,
- const V1_1::ProgramInfo& info) {
- halResult = result;
- if (result != Result::OK) return;
- jInfo = convert::ProgramInfoFromHal(env, info);
- });
- } else {
- hidlResult = halTuner10->getProgramInformation([&](Result result,
- const V1_0::ProgramInfo& info) {
- halResult = result;
- if (result != Result::OK) return;
- jInfo = convert::ProgramInfoFromHal(env, info, ctx.mBand);
- });
- }
-
- if (jInfo != nullptr) return jInfo.release();
- convert::ThrowIfFailed(env, hidlResult, halResult);
- return nullptr;
-}
-
static bool nativeStartBackgroundScan(JNIEnv *env, jobject obj, jlong nativeContext) {
ALOGV("%s", __func__);
auto halTuner = getHalTuner11(nativeContext);
@@ -541,21 +508,6 @@
return jResults.release();
}
-static bool nativeIsAntennaConnected(JNIEnv *env, jobject obj, jlong nativeContext) {
- ALOGV("%s", __func__);
- auto halTuner = getHalTuner(nativeContext);
- if (halTuner == nullptr) return false;
-
- bool isConnected = false;
- Result halResult;
- auto hidlResult = halTuner->getConfiguration([&](Result result, const BandConfig& config) {
- halResult = result;
- isConnected = config.antennaConnected;
- });
- convert::ThrowIfFailed(env, hidlResult, halResult);
- return isConnected;
-}
-
static const JNINativeMethod gTunerMethods[] = {
{ "nativeInit", "(IZI)J", (void*)nativeInit },
{ "nativeFinalize", "(J)V", (void*)nativeFinalize },
@@ -570,8 +522,6 @@
{ "nativeTune", "(JLandroid/hardware/radio/ProgramSelector;)V", (void*)nativeTune },
{ "nativeCancel", "(J)V", (void*)nativeCancel },
{ "nativeCancelAnnouncement", "(J)V", (void*)nativeCancelAnnouncement },
- { "nativeGetProgramInformation", "(J)Landroid/hardware/radio/RadioManager$ProgramInfo;",
- (void*)nativeGetProgramInformation },
{ "nativeStartBackgroundScan", "(J)Z", (void*)nativeStartBackgroundScan },
{ "nativeGetProgramList", "(JLjava/util/Map;)Ljava/util/List;",
(void*)nativeGetProgramList },
@@ -580,7 +530,6 @@
{ "nativeSetAnalogForced", "(JZ)V", (void*)nativeSetAnalogForced },
{ "nativeSetParameters", "(JLjava/util/Map;)Ljava/util/Map;", (void*)nativeSetParameters },
{ "nativeGetParameters", "(JLjava/util/List;)Ljava/util/Map;", (void*)nativeGetParameters },
- { "nativeIsAntennaConnected", "(J)Z", (void*)nativeIsAntennaConnected },
};
} // namespace Tuner
diff --git a/services/usb/Android.bp b/services/usb/Android.bp
index 0cd9ac3..feb7b76 100644
--- a/services/usb/Android.bp
+++ b/services/usb/Android.bp
@@ -10,5 +10,6 @@
static_libs: [
"android.hardware.usb-V1.0-java",
"android.hardware.usb-V1.1-java",
+ "android.hardware.usb.gadget-V1.0-java",
],
}
diff --git a/services/usb/java/com/android/server/usb/UsbDeviceManager.java b/services/usb/java/com/android/server/usb/UsbDeviceManager.java
index 4a7072d..e3e5e3e 100644
--- a/services/usb/java/com/android/server/usb/UsbDeviceManager.java
+++ b/services/usb/java/com/android/server/usb/UsbDeviceManager.java
@@ -41,13 +41,21 @@
import android.hardware.usb.UsbManager;
import android.hardware.usb.UsbPort;
import android.hardware.usb.UsbPortStatus;
+import android.hardware.usb.gadget.V1_0.GadgetFunction;
+import android.hardware.usb.gadget.V1_0.IUsbGadget;
+import android.hardware.usb.gadget.V1_0.IUsbGadgetCallback;
+import android.hardware.usb.gadget.V1_0.Status;
+import android.hidl.manager.V1_0.IServiceManager;
+import android.hidl.manager.V1_0.IServiceNotification;
import android.os.BatteryManager;
import android.os.Environment;
import android.os.FileUtils;
import android.os.Handler;
+import android.os.HwBinder;
import android.os.Looper;
import android.os.Message;
import android.os.ParcelFileDescriptor;
+import android.os.RemoteException;
import android.os.SystemClock;
import android.os.SystemProperties;
import android.os.UEventObserver;
@@ -75,8 +83,10 @@
import java.util.Iterator;
import java.util.Locale;
import java.util.Map;
+import java.util.NoSuchElementException;
import java.util.Scanner;
import java.util.Set;
+import java.util.StringJoiner;
/**
* UsbDeviceManager manages USB state in device mode.
@@ -87,22 +97,6 @@
private static final boolean DEBUG = false;
/**
- * The persistent property which stores whether adb is enabled or not.
- * May also contain vendor-specific default functions for testing purposes.
- */
- private static final String USB_PERSISTENT_CONFIG_PROPERTY = "persist.sys.usb.config";
-
- /**
- * The non-persistent property which stores the current USB settings.
- */
- private static final String USB_CONFIG_PROPERTY = "sys.usb.config";
-
- /**
- * The non-persistent property which stores the current USB actual state.
- */
- private static final String USB_STATE_PROPERTY = "sys.usb.state";
-
- /**
* The SharedPreference setting per user that stores the screen unlocked functions between
* sessions.
*/
@@ -142,6 +136,10 @@
private static final int MSG_LOCALE_CHANGED = 11;
private static final int MSG_SET_SCREEN_UNLOCKED_FUNCTIONS = 12;
private static final int MSG_UPDATE_SCREEN_LOCK = 13;
+ private static final int MSG_SET_CHARGING_FUNCTIONS = 14;
+ private static final int MSG_SET_FUNCTIONS_TIMEOUT = 15;
+ private static final int MSG_GET_CURRENT_USB_FUNCTIONS = 16;
+ private static final int MSG_FUNCTION_SWITCH_TIMEOUT = 17;
private static final int AUDIO_MODE_SOURCE = 1;
@@ -157,9 +155,9 @@
private static final String BOOT_MODE_PROPERTY = "ro.bootmode";
private static final String ADB_NOTIFICATION_CHANNEL_ID_TV = "usbdevicemanager.adb.tv";
-
private UsbHandler mHandler;
private boolean mBootCompleted;
+ private boolean mSystemReady;
private final Object mLock = new Object();
@@ -175,7 +173,6 @@
private boolean mMidiEnabled;
private int mMidiCard;
private int mMidiDevice;
- private HashMap<String, HashMap<String, Pair<String, String>>> mOemModeMap;
private String[] mAccessoryStrings;
private UsbDebuggingManager mDebuggingManager;
private final UsbAlsaManager mUsbAlsaManager;
@@ -267,9 +264,27 @@
mHasUsbAccessory = pm.hasSystemFeature(PackageManager.FEATURE_USB_ACCESSORY);
initRndisAddress();
- readOemUsbOverrideConfig();
+ boolean halNotPresent = false;
+ try {
+ IUsbGadget.getService(true);
+ } catch (RemoteException e) {
+ Slog.e(TAG, "USB GADGET HAL present but exception thrown", e);
+ } catch (NoSuchElementException e) {
+ halNotPresent = true;
+ Slog.i(TAG, "USB GADGET HAL not present in the device", e);
+ }
- mHandler = new UsbHandler(FgThread.get().getLooper());
+ if (halNotPresent) {
+ /**
+ * Initialze the legacy UsbHandler
+ */
+ mHandler = new UsbHandlerLegacy(FgThread.get().getLooper(), mContext);
+ } else {
+ /**
+ * Initialize HAL based UsbHandler
+ */
+ mHandler = new UsbHandlerHal(FgThread.get().getLooper());
+ }
if (nativeIsStartRequested()) {
if (DEBUG) Slog.d(TAG, "accessory attached at boot");
@@ -367,15 +382,6 @@
massStorageSupported = primary != null && primary.allowMassStorage();
mUseUsbNotification = !massStorageSupported && mContext.getResources().getBoolean(
com.android.internal.R.bool.config_usbChargingMessage);
-
- // make sure the ADB_ENABLED setting value matches the current state
- try {
- Settings.Global.putInt(mContentResolver,
- Settings.Global.ADB_ENABLED, mAdbEnabled ? 1 : 0);
- } catch (SecurityException e) {
- // If UserManager.DISALLOW_DEBUGGING_FEATURES is on, that this setting can't be changed.
- Slog.d(TAG, "ADB_ENABLED is restricted.");
- }
mHandler.sendEmptyMessage(MSG_SYSTEM_READY);
}
@@ -457,7 +463,7 @@
return context.getSharedPreferences(prefsFile, Context.MODE_PRIVATE);
}
- private final class UsbHandler extends Handler {
+ private abstract class UsbHandler extends Handler {
// current USB state
private boolean mConnected;
@@ -465,78 +471,53 @@
private boolean mSourcePower;
private boolean mSinkPower;
private boolean mConfigured;
- private boolean mUsbDataUnlocked;
+ protected boolean mUsbDataUnlocked;
private boolean mAudioAccessoryConnected;
private boolean mAudioAccessorySupported;
- private String mCurrentFunctions;
- private boolean mCurrentFunctionsApplied;
+ protected String mCurrentFunctions;
+ protected boolean mCurrentFunctionsApplied;
private UsbAccessory mCurrentAccessory;
private int mUsbNotificationId;
private boolean mAdbNotificationShown;
private int mCurrentUser;
private boolean mUsbCharging;
- private String mCurrentOemFunctions;
private boolean mHideUsbNotification;
private boolean mSupportsAllCombinations;
private String mScreenUnlockedFunctions = UsbManager.USB_FUNCTION_NONE;
private boolean mScreenLocked;
+ protected boolean mCurrentUsbFunctionsRequested;
+ protected boolean mCurrentUsbFunctionsReceived;
+
+ /**
+ * The persistent property which stores whether adb is enabled or not.
+ * May also contain vendor-specific default functions for testing purposes.
+ */
+ protected static final String USB_PERSISTENT_CONFIG_PROPERTY = "persist.sys.usb.config";
public UsbHandler(Looper looper) {
super(looper);
- try {
- // Restore default functions.
- mCurrentOemFunctions = SystemProperties.get(UsbDeviceManager.getPersistProp(false),
- UsbManager.USB_FUNCTION_NONE);
- if (isNormalBoot()) {
- mCurrentFunctions = SystemProperties.get(USB_CONFIG_PROPERTY,
- UsbManager.USB_FUNCTION_NONE);
- mCurrentFunctionsApplied = mCurrentFunctions.equals(
- SystemProperties.get(USB_STATE_PROPERTY));
- } else {
- mCurrentFunctions = SystemProperties.get(getPersistProp(true),
- UsbManager.USB_FUNCTION_NONE);
- mCurrentFunctionsApplied = SystemProperties.get(USB_CONFIG_PROPERTY,
- UsbManager.USB_FUNCTION_NONE).equals(
- SystemProperties.get(USB_STATE_PROPERTY));
- }
+ mCurrentUser = ActivityManager.getCurrentUser();
+ mScreenLocked = true;
- mCurrentUser = ActivityManager.getCurrentUser();
- mScreenLocked = true;
+ /*
+ * Use the normal bootmode persistent prop to maintain state of adb across
+ * all boot modes.
+ */
+ mAdbEnabled = UsbManager.containsFunction(
+ SystemProperties.get(USB_PERSISTENT_CONFIG_PROPERTY),
+ UsbManager.USB_FUNCTION_ADB);
- /*
- * Use the normal bootmode persistent prop to maintain state of adb across
- * all boot modes.
- */
- mAdbEnabled = UsbManager.containsFunction(
- SystemProperties.get(USB_PERSISTENT_CONFIG_PROPERTY),
- UsbManager.USB_FUNCTION_ADB);
-
- /*
- * Previous versions can set persist config to mtp/ptp but it does not
- * get reset on OTA. Reset the property here instead.
- */
- String persisted = SystemProperties.get(USB_PERSISTENT_CONFIG_PROPERTY);
- if (UsbManager.containsFunction(persisted, UsbManager.USB_FUNCTION_MTP)
- || UsbManager.containsFunction(persisted, UsbManager.USB_FUNCTION_PTP)) {
- SystemProperties.set(USB_PERSISTENT_CONFIG_PROPERTY,
- UsbManager.removeFunction(UsbManager.removeFunction(persisted,
- UsbManager.USB_FUNCTION_MTP), UsbManager.USB_FUNCTION_PTP));
- }
-
- String state = FileUtils.readTextFile(new File(STATE_PATH), 0, null).trim();
- updateState(state);
-
- // register observer to listen for settings changes
- mContentResolver.registerContentObserver(
- Settings.Global.getUriFor(Settings.Global.ADB_ENABLED),
- false, new AdbSettingsObserver());
-
- // Watch for USB configuration changes
- mUEventObserver.startObserving(USB_STATE_MATCH);
- mUEventObserver.startObserving(ACCESSORY_START_MATCH);
- } catch (Exception e) {
- Slog.e(TAG, "Error initializing UsbHandler", e);
+ /*
+ * Previous versions can set persist config to mtp/ptp but it does not
+ * get reset on OTA. Reset the property here instead.
+ */
+ String persisted = SystemProperties.get(USB_PERSISTENT_CONFIG_PROPERTY);
+ if (UsbManager.containsFunction(persisted, UsbManager.USB_FUNCTION_MTP)
+ || UsbManager.containsFunction(persisted, UsbManager.USB_FUNCTION_PTP)) {
+ SystemProperties.set(USB_PERSISTENT_CONFIG_PROPERTY,
+ UsbManager.removeFunction(UsbManager.removeFunction(persisted,
+ UsbManager.USB_FUNCTION_MTP), UsbManager.USB_FUNCTION_PTP));
}
}
@@ -562,6 +543,21 @@
sendMessage(m);
}
+ public void sendMessage(int what, boolean arg1, boolean arg2) {
+ removeMessages(what);
+ Message m = Message.obtain(this, what);
+ m.arg1 = (arg1 ? 1 : 0);
+ m.arg2 = (arg2 ? 1 : 0);
+ sendMessage(m);
+ }
+
+ public void sendMessageDelayed(int what, boolean arg, long delayMillis) {
+ removeMessages(what);
+ Message m = Message.obtain(this, what);
+ m.arg1 = (arg ? 1 : 0);
+ sendMessageDelayed(m, delayMillis);
+ }
+
public void updateState(String state) {
int connected, configured;
@@ -579,6 +575,7 @@
return;
}
removeMessages(MSG_UPDATE_STATE);
+ if (connected == 1) removeMessages(MSG_FUNCTION_SWITCH_TIMEOUT);
Message msg = Message.obtain(this, MSG_UPDATE_STATE);
msg.arg1 = connected;
msg.arg2 = configured;
@@ -601,28 +598,6 @@
sendMessageDelayed(msg, UPDATE_DELAY);
}
- private boolean waitForState(String state) {
- // wait for the transition to complete.
- // give up after 1 second.
- String value = null;
- for (int i = 0; i < 20; i++) {
- // State transition is done when sys.usb.state is set to the new configuration
- value = SystemProperties.get(USB_STATE_PROPERTY);
- if (state.equals(value)) return true;
- SystemClock.sleep(50);
- }
- Slog.e(TAG, "waitForState(" + state + ") FAILED: got " + value);
- return false;
- }
-
- private void setUsbConfig(String config) {
- if (DEBUG) Slog.d(TAG, "setUsbConfig(" + config + ")");
- // set the new configuration
- // we always set it due to b/23631400, where adbd was getting killed
- // and not restarted due to property timeouts on some devices
- SystemProperties.set(USB_CONFIG_PROPERTY, config);
- }
-
private void setAdbEnabled(boolean enable) {
if (DEBUG) Slog.d(TAG, "setAdbEnabled: " + enable);
if (enable != mAdbEnabled) {
@@ -649,114 +624,7 @@
}
}
- /**
- * Evaluates USB function policies and applies the change accordingly.
- */
- private void setEnabledFunctions(String functions, boolean forceRestart,
- boolean usbDataUnlocked) {
- if (DEBUG) {
- Slog.d(TAG, "setEnabledFunctions functions=" + functions + ", "
- + "forceRestart=" + forceRestart + ", usbDataUnlocked=" + usbDataUnlocked);
- }
-
- if (usbDataUnlocked != mUsbDataUnlocked) {
- mUsbDataUnlocked = usbDataUnlocked;
- updateUsbNotification(false);
- forceRestart = true;
- }
-
- // Try to set the enabled functions.
- final String oldFunctions = mCurrentFunctions;
- final boolean oldFunctionsApplied = mCurrentFunctionsApplied;
- if (trySetEnabledFunctions(functions, forceRestart)) {
- return;
- }
-
- // Didn't work. Try to revert changes.
- // We always reapply the policy in case certain constraints changed such as
- // user restrictions independently of any other new functions we were
- // trying to activate.
- if (oldFunctionsApplied && !oldFunctions.equals(functions)) {
- Slog.e(TAG, "Failsafe 1: Restoring previous USB functions.");
- if (trySetEnabledFunctions(oldFunctions, false)) {
- return;
- }
- }
-
- // Still didn't work. Try to restore the default functions.
- Slog.e(TAG, "Failsafe 2: Restoring default USB functions.");
- if (trySetEnabledFunctions(null, false)) {
- return;
- }
-
- // Now we're desperate. Ignore the default functions.
- // Try to get ADB working if enabled.
- Slog.e(TAG, "Failsafe 3: Restoring empty function list (with ADB if enabled).");
- if (trySetEnabledFunctions(UsbManager.USB_FUNCTION_NONE, false)) {
- return;
- }
-
- // Ouch.
- Slog.e(TAG, "Unable to set any USB functions!");
- }
-
- private boolean isNormalBoot() {
- String bootMode = SystemProperties.get(BOOT_MODE_PROPERTY, "unknown");
- return bootMode.equals(NORMAL_BOOT) || bootMode.equals("unknown");
- }
-
- private boolean trySetEnabledFunctions(String functions, boolean forceRestart) {
- if (functions == null || applyAdbFunction(functions)
- .equals(UsbManager.USB_FUNCTION_NONE)) {
- functions = getChargingFunctions();
- }
- functions = applyAdbFunction(functions);
-
- String oemFunctions = applyOemOverrideFunction(functions);
-
- if (!isNormalBoot() && !mCurrentFunctions.equals(functions)) {
- SystemProperties.set(getPersistProp(true), functions);
- }
-
- if ((!functions.equals(oemFunctions) &&
- !mCurrentOemFunctions.equals(oemFunctions))
- || !mCurrentFunctions.equals(functions)
- || !mCurrentFunctionsApplied
- || forceRestart) {
- Slog.i(TAG, "Setting USB config to " + functions);
- mCurrentFunctions = functions;
- mCurrentOemFunctions = oemFunctions;
- mCurrentFunctionsApplied = false;
-
- // Kick the USB stack to close existing connections.
- setUsbConfig(UsbManager.USB_FUNCTION_NONE);
-
- if (!waitForState(UsbManager.USB_FUNCTION_NONE)) {
- Slog.e(TAG, "Failed to kick USB config");
- return false;
- }
-
- // Set the new USB configuration.
- setUsbConfig(oemFunctions);
-
- if (mBootCompleted
- && (UsbManager.containsFunction(functions, UsbManager.USB_FUNCTION_MTP)
- || UsbManager.containsFunction(functions, UsbManager.USB_FUNCTION_PTP))) {
- // Start up dependent services.
- updateUsbStateBroadcastIfNeeded(true);
- }
-
- if (!waitForState(oemFunctions)) {
- Slog.e(TAG, "Failed to switch USB config to " + functions);
- return false;
- }
-
- mCurrentFunctionsApplied = true;
- }
- return true;
- }
-
- private String applyAdbFunction(String functions) {
+ protected String applyAdbFunction(String functions) {
// Do not pass null pointer to the UsbManager.
// There isnt a check there.
if (functions == null) {
@@ -838,7 +706,7 @@
return false;
}
- private void updateUsbStateBroadcastIfNeeded(boolean configChanged) {
+ protected void updateUsbStateBroadcastIfNeeded(boolean configChanged) {
// send a sticky broadcast containing current USB state
Intent intent = new Intent(UsbManager.ACTION_USB_STATE);
intent.addFlags(Intent.FLAG_RECEIVER_REPLACE_PENDING
@@ -956,7 +824,8 @@
updateCurrentAccessory();
}
if (mBootCompleted) {
- if (!mConnected && !hasMessages(MSG_ACCESSORY_MODE_ENTER_TIMEOUT)) {
+ if (!mConnected && !hasMessages(MSG_ACCESSORY_MODE_ENTER_TIMEOUT)
+ && !hasMessages(MSG_FUNCTION_SWITCH_TIMEOUT)) {
// restore defaults when USB is disconnected
if (!mScreenLocked
&& !UsbManager.USB_FUNCTION_NONE.equals(
@@ -1082,7 +951,7 @@
if (!UsbManager.USB_FUNCTION_NONE.equals(mScreenUnlockedFunctions)
&& (UsbManager.USB_FUNCTION_ADB.equals(mCurrentFunctions)
|| (UsbManager.USB_FUNCTION_MTP.equals(mCurrentFunctions)
- && !mUsbDataUnlocked))) {
+ && !mUsbDataUnlocked))) {
// Set the screen unlocked functions if current function is charging.
setScreenUnlockedFunctions();
}
@@ -1097,9 +966,8 @@
mCurrentFunctions, forceRestart, mUsbDataUnlocked && !forceRestart);
break;
case MSG_SYSTEM_READY:
- updateUsbNotification(false);
- updateAdbNotification(false);
- updateUsbFunctions();
+ mSystemReady = true;
+ finishBoot();
break;
case MSG_LOCALE_CHANGED:
updateAdbNotification(true);
@@ -1107,23 +975,7 @@
break;
case MSG_BOOT_COMPLETED:
mBootCompleted = true;
- if (mPendingBootBroadcast) {
- updateUsbStateBroadcastIfNeeded(false);
- mPendingBootBroadcast = false;
- }
-
- if (!mScreenLocked
- && !UsbManager.USB_FUNCTION_NONE.equals(mScreenUnlockedFunctions)) {
- setScreenUnlockedFunctions();
- } else {
- setEnabledFunctions(null, false, false);
- }
- if (mCurrentAccessory != null) {
- getCurrentSettings().accessoryAttached(mCurrentAccessory);
- }
- if (mDebuggingManager != null) {
- mDebuggingManager.setAdbEnabled(mAdbEnabled);
- }
+ finishBoot();
break;
case MSG_USER_SWITCHED: {
if (mCurrentUser != msg.arg1) {
@@ -1153,6 +1005,41 @@
}
}
+ protected void finishBoot() {
+ if (mBootCompleted && mCurrentUsbFunctionsReceived && mSystemReady) {
+ if (mPendingBootBroadcast) {
+ updateUsbStateBroadcastIfNeeded(false);
+ mPendingBootBroadcast = false;
+ }
+ if (!mScreenLocked
+ && !UsbManager.USB_FUNCTION_NONE.equals(mScreenUnlockedFunctions)) {
+ setScreenUnlockedFunctions();
+ } else {
+ setEnabledFunctions(null, false, false);
+ }
+ if (mCurrentAccessory != null) {
+ getCurrentSettings().accessoryAttached(mCurrentAccessory);
+ }
+ if (mDebuggingManager != null) {
+ mDebuggingManager.setAdbEnabled(mAdbEnabled);
+ }
+
+ // make sure the ADB_ENABLED setting value matches the current state
+ try {
+ Settings.Global.putInt(mContentResolver,
+ Settings.Global.ADB_ENABLED, mAdbEnabled ? 1 : 0);
+ } catch (SecurityException e) {
+ // If UserManager.DISALLOW_DEBUGGING_FEATURES is on, that this setting can't
+ // be changed.
+ Slog.d(TAG, "ADB_ENABLED is restricted.");
+ }
+
+ updateUsbNotification(false);
+ updateAdbNotification(false);
+ updateUsbFunctions();
+ }
+ }
+
private boolean isUsbDataTransferActive() {
return UsbManager.containsFunction(mCurrentFunctions, UsbManager.USB_FUNCTION_MTP)
|| UsbManager.containsFunction(mCurrentFunctions, UsbManager.USB_FUNCTION_PTP);
@@ -1162,7 +1049,7 @@
return mCurrentAccessory;
}
- private void updateUsbNotification(boolean force) {
+ protected void updateUsbNotification(boolean force) {
if (mNotificationManager == null || !mUseUsbNotification
|| ("0".equals(SystemProperties.get("persist.charging.notify")))) {
return;
@@ -1262,18 +1149,18 @@
}
Notification.Builder builder = new Notification.Builder(mContext, channel)
- .setSmallIcon(com.android.internal.R.drawable.stat_sys_adb)
- .setWhen(0)
- .setOngoing(true)
- .setTicker(title)
- .setDefaults(0) // please be quiet
- .setColor(mContext.getColor(
- com.android.internal.R.color
- .system_notification_accent_color))
- .setContentTitle(title)
- .setContentText(message)
- .setContentIntent(pi)
- .setVisibility(Notification.VISIBILITY_PUBLIC);
+ .setSmallIcon(com.android.internal.R.drawable.stat_sys_adb)
+ .setWhen(0)
+ .setOngoing(true)
+ .setTicker(title)
+ .setDefaults(0) // please be quiet
+ .setColor(mContext.getColor(
+ com.android.internal.R.color
+ .system_notification_accent_color))
+ .setContentTitle(title)
+ .setContentText(message)
+ .setContentIntent(pi)
+ .setVisibility(Notification.VISIBILITY_PUBLIC);
if (titleRes
== com.android.internal.R.string
@@ -1291,7 +1178,7 @@
}
}
- private void updateAdbNotification(boolean force) {
+ protected void updateAdbNotification(boolean force) {
if (mNotificationManager == null) return;
final int id = SystemMessage.NOTE_ADB_ACTIVE;
final int titleRes = com.android.internal.R.string.adb_active_notification_title;
@@ -1343,22 +1230,23 @@
}
}
- private String getChargingFunctions() {
- String func = SystemProperties.get(getPersistProp(true),
- UsbManager.USB_FUNCTION_NONE);
+ protected String getChargingFunctions() {
// if ADB is enabled, reset functions to ADB
// else enable MTP as usual.
- if (UsbManager.containsFunction(func, UsbManager.USB_FUNCTION_ADB)) {
+ if (mAdbEnabled) {
return UsbManager.USB_FUNCTION_ADB;
} else {
return UsbManager.USB_FUNCTION_MTP;
}
}
+ public boolean isFunctionEnabled(String function) {
+ return UsbManager.containsFunction(mCurrentFunctions, function);
+ }
+
public void dump(IndentingPrintWriter pw) {
pw.println("USB Device State:");
pw.println(" mCurrentFunctions: " + mCurrentFunctions);
- pw.println(" mCurrentOemFunctions: " + mCurrentOemFunctions);
pw.println(" mCurrentFunctionsApplied: " + mCurrentFunctionsApplied);
pw.println(" mScreenUnlockedFunctions: " + mScreenUnlockedFunctions);
pw.println(" mScreenLocked: " + mScreenLocked);
@@ -1372,6 +1260,7 @@
pw.println(" mUsbCharging: " + mUsbCharging);
pw.println(" mHideUsbNotification: " + mHideUsbNotification);
pw.println(" mAudioAccessoryConnected: " + mAudioAccessoryConnected);
+ pw.println(" mAdbEnabled: " + mAdbEnabled);
try {
pw.println(" Kernel state: "
@@ -1382,6 +1271,675 @@
pw.println("IOException: " + e);
}
}
+
+ /**
+ * Evaluates USB function policies and applies the change accordingly.
+ */
+ protected abstract void setEnabledFunctions(String functions, boolean forceRestart,
+ boolean usbDataUnlocked);
+
+ }
+
+ private final class UsbHandlerLegacy extends UsbHandler {
+ /**
+ * The non-persistent property which stores the current USB settings.
+ */
+ private static final String USB_CONFIG_PROPERTY = "sys.usb.config";
+
+ /**
+ * The non-persistent property which stores the current USB actual state.
+ */
+ private static final String USB_STATE_PROPERTY = "sys.usb.state";
+
+ private HashMap<String, HashMap<String, Pair<String, String>>> mOemModeMap;
+ private String mCurrentOemFunctions;
+
+ UsbHandlerLegacy(Looper looper, Context context) {
+ super(looper);
+ try {
+ readOemUsbOverrideConfig(context);
+ // Restore default functions.
+ mCurrentOemFunctions = SystemProperties.get(getPersistProp(false),
+ UsbManager.USB_FUNCTION_NONE);
+ if (isNormalBoot()) {
+ mCurrentFunctions = SystemProperties.get(USB_CONFIG_PROPERTY,
+ UsbManager.USB_FUNCTION_NONE);
+ mCurrentFunctionsApplied = mCurrentFunctions.equals(
+ SystemProperties.get(USB_STATE_PROPERTY));
+ } else {
+ mCurrentFunctions = SystemProperties.get(getPersistProp(true),
+ UsbManager.USB_FUNCTION_NONE);
+ mCurrentFunctionsApplied = SystemProperties.get(USB_CONFIG_PROPERTY,
+ UsbManager.USB_FUNCTION_NONE).equals(
+ SystemProperties.get(USB_STATE_PROPERTY));
+ }
+ mCurrentUsbFunctionsReceived = true;
+
+ String state = FileUtils.readTextFile(new File(STATE_PATH), 0, null).trim();
+ updateState(state);
+
+ // register observer to listen for settings changes
+ mContentResolver.registerContentObserver(
+ Settings.Global.getUriFor(Settings.Global.ADB_ENABLED),
+ false, new AdbSettingsObserver());
+
+ // Watch for USB configuration changes
+ mUEventObserver.startObserving(USB_STATE_MATCH);
+ mUEventObserver.startObserving(ACCESSORY_START_MATCH);
+ } catch (Exception e) {
+ Slog.e(TAG, "Error initializing UsbHandler", e);
+ }
+ }
+
+ private void readOemUsbOverrideConfig(Context context) {
+ String[] configList = mContext.getResources().getStringArray(
+ com.android.internal.R.array.config_oemUsbModeOverride);
+
+ if (configList != null) {
+ for (String config : configList) {
+ String[] items = config.split(":");
+ if (items.length == 3 || items.length == 4) {
+ if (mOemModeMap == null) {
+ mOemModeMap = new HashMap<>();
+ }
+ HashMap<String, Pair<String, String>> overrideMap =
+ mOemModeMap.get(items[0]);
+ if (overrideMap == null) {
+ overrideMap = new HashMap<>();
+ mOemModeMap.put(items[0], overrideMap);
+ }
+
+ // Favoring the first combination if duplicate exists
+ if (!overrideMap.containsKey(items[1])) {
+ if (items.length == 3) {
+ overrideMap.put(items[1], new Pair<>(items[2], ""));
+ } else {
+ overrideMap.put(items[1], new Pair<>(items[2], items[3]));
+ }
+ }
+ }
+ }
+ }
+ }
+
+ private String applyOemOverrideFunction(String usbFunctions) {
+ if ((usbFunctions == null) || (mOemModeMap == null)) {
+ return usbFunctions;
+ }
+
+ String bootMode = SystemProperties.get(BOOT_MODE_PROPERTY, "unknown");
+ Slog.d(TAG, "applyOemOverride usbfunctions=" + usbFunctions + " bootmode=" + bootMode);
+
+ Map<String, Pair<String, String>> overridesMap =
+ mOemModeMap.get(bootMode);
+ // Check to ensure that the oem is not overriding in the normal
+ // boot mode
+ if (overridesMap != null && !(bootMode.equals(NORMAL_BOOT)
+ || bootMode.equals("unknown"))) {
+ Pair<String, String> overrideFunctions =
+ overridesMap.get(usbFunctions);
+ if (overrideFunctions != null) {
+ Slog.d(TAG, "OEM USB override: " + usbFunctions
+ + " ==> " + overrideFunctions.first
+ + " persist across reboot "
+ + overrideFunctions.second);
+ if (!overrideFunctions.second.equals("")) {
+ String newFunction;
+ if (mAdbEnabled) {
+ newFunction = UsbManager.addFunction(overrideFunctions.second,
+ UsbManager.USB_FUNCTION_ADB);
+ } else {
+ newFunction = overrideFunctions.second;
+ }
+ Slog.d(TAG, "OEM USB override persisting: " + newFunction + "in prop: "
+ + getPersistProp(false));
+ SystemProperties.set(getPersistProp(false),
+ newFunction);
+ }
+ return overrideFunctions.first;
+ } else if (mAdbEnabled) {
+ String newFunction = UsbManager.addFunction(UsbManager.USB_FUNCTION_NONE,
+ UsbManager.USB_FUNCTION_ADB);
+ SystemProperties.set(getPersistProp(false),
+ newFunction);
+ } else {
+ SystemProperties.set(getPersistProp(false),
+ UsbManager.USB_FUNCTION_NONE);
+ }
+ }
+ // return passed in functions as is.
+ return usbFunctions;
+ }
+
+ private boolean waitForState(String state) {
+ // wait for the transition to complete.
+ // give up after 1 second.
+ String value = null;
+ for (int i = 0; i < 20; i++) {
+ // State transition is done when sys.usb.state is set to the new configuration
+ value = SystemProperties.get(USB_STATE_PROPERTY);
+ if (state.equals(value)) return true;
+ SystemClock.sleep(50);
+ }
+ Slog.e(TAG, "waitForState(" + state + ") FAILED: got " + value);
+ return false;
+ }
+
+ private void setUsbConfig(String config) {
+ if (DEBUG) Slog.d(TAG, "setUsbConfig(" + config + ")");
+ /**
+ * set the new configuration
+ * we always set it due to b/23631400, where adbd was getting killed
+ * and not restarted due to property timeouts on some devices
+ */
+ SystemProperties.set(USB_CONFIG_PROPERTY, config);
+ }
+
+ @Override
+ protected void setEnabledFunctions(String functions, boolean forceRestart,
+ boolean usbDataUnlocked) {
+ if (DEBUG) {
+ Slog.d(TAG, "setEnabledFunctions functions=" + functions + ", "
+ + "forceRestart=" + forceRestart + ", usbDataUnlocked=" + usbDataUnlocked);
+ }
+
+ if (usbDataUnlocked != mUsbDataUnlocked) {
+ mUsbDataUnlocked = usbDataUnlocked;
+ updateUsbNotification(false);
+ forceRestart = true;
+ }
+
+ /**
+ * Try to set the enabled functions.
+ */
+ final String oldFunctions = mCurrentFunctions;
+ final boolean oldFunctionsApplied = mCurrentFunctionsApplied;
+ if (trySetEnabledFunctions(functions, forceRestart)) {
+ return;
+ }
+
+ /**
+ * Didn't work. Try to revert changes.
+ * We always reapply the policy in case certain constraints changed such as
+ * user restrictions independently of any other new functions we were
+ * trying to activate.
+ */
+ if (oldFunctionsApplied && !oldFunctions.equals(functions)) {
+ Slog.e(TAG, "Failsafe 1: Restoring previous USB functions.");
+ if (trySetEnabledFunctions(oldFunctions, false)) {
+ return;
+ }
+ }
+
+ /**
+ * Still didn't work. Try to restore the default functions.
+ */
+ Slog.e(TAG, "Failsafe 2: Restoring default USB functions.");
+ if (trySetEnabledFunctions(null, false)) {
+ return;
+ }
+
+ /**
+ * Now we're desperate. Ignore the default functions.
+ * Try to get ADB working if enabled.
+ */
+ Slog.e(TAG, "Failsafe 3: Restoring empty function list (with ADB if enabled).");
+ if (trySetEnabledFunctions(UsbManager.USB_FUNCTION_NONE, false)) {
+ return;
+ }
+
+ /**
+ * Ouch.
+ */
+ Slog.e(TAG, "Unable to set any USB functions!");
+ }
+
+ private boolean isNormalBoot() {
+ String bootMode = SystemProperties.get(BOOT_MODE_PROPERTY, "unknown");
+ return bootMode.equals(NORMAL_BOOT) || bootMode.equals("unknown");
+ }
+
+ private boolean trySetEnabledFunctions(String functions, boolean forceRestart) {
+ if (functions == null || applyAdbFunction(functions)
+ .equals(UsbManager.USB_FUNCTION_NONE)) {
+ functions = getChargingFunctions();
+ }
+ functions = applyAdbFunction(functions);
+
+ String oemFunctions = applyOemOverrideFunction(functions);
+
+ if (!isNormalBoot() && !mCurrentFunctions.equals(functions)) {
+ SystemProperties.set(getPersistProp(true), functions);
+ }
+
+ if ((!functions.equals(oemFunctions)
+ && !mCurrentOemFunctions.equals(oemFunctions))
+ || !mCurrentFunctions.equals(functions)
+ || !mCurrentFunctionsApplied
+ || forceRestart) {
+ Slog.i(TAG, "Setting USB config to " + functions);
+ mCurrentFunctions = functions;
+ mCurrentOemFunctions = oemFunctions;
+ mCurrentFunctionsApplied = false;
+
+ /**
+ * Kick the USB stack to close existing connections.
+ */
+ setUsbConfig(UsbManager.USB_FUNCTION_NONE);
+
+ if (!waitForState(UsbManager.USB_FUNCTION_NONE)) {
+ Slog.e(TAG, "Failed to kick USB config");
+ return false;
+ }
+
+ /**
+ * Set the new USB configuration.
+ */
+ setUsbConfig(oemFunctions);
+
+ if (mBootCompleted
+ && (UsbManager.containsFunction(functions, UsbManager.USB_FUNCTION_MTP)
+ || UsbManager.containsFunction(functions, UsbManager.USB_FUNCTION_PTP))) {
+ /**
+ * Start up dependent services.
+ */
+ updateUsbStateBroadcastIfNeeded(true);
+ }
+
+ if (!waitForState(oemFunctions)) {
+ Slog.e(TAG, "Failed to switch USB config to " + functions);
+ return false;
+ }
+
+ mCurrentFunctionsApplied = true;
+ }
+ return true;
+ }
+
+ private String getPersistProp(boolean functions) {
+ String bootMode = SystemProperties.get(BOOT_MODE_PROPERTY, "unknown");
+ String persistProp = USB_PERSISTENT_CONFIG_PROPERTY;
+ if (!(bootMode.equals(NORMAL_BOOT) || bootMode.equals("unknown"))) {
+ if (functions) {
+ persistProp = "persist.sys.usb." + bootMode + ".func";
+ } else {
+ persistProp = "persist.sys.usb." + bootMode + ".config";
+ }
+ }
+ return persistProp;
+ }
+ }
+
+ private final class UsbHandlerHal extends UsbHandler {
+
+ /**
+ * Proxy object for the usb gadget hal daemon.
+ */
+ @GuardedBy("mGadgetProxyLock")
+ private IUsbGadget mGadgetProxy;
+
+ private final Object mGadgetProxyLock = new Object();
+
+ /**
+ * Cookie sent for usb gadget hal death notification.
+ */
+ private static final int USB_GADGET_HAL_DEATH_COOKIE = 2000;
+
+ /**
+ * Keeps track of the latest setCurrentUsbFunctions request number.
+ */
+ private int mCurrentRequest = 0;
+
+ /**
+ * The maximum time for which the UsbDeviceManager would wait once
+ * setCurrentUsbFunctions is called.
+ */
+ private static final int SET_FUNCTIONS_TIMEOUT_MS = 3000;
+
+ /**
+ * Conseration leeway to make sure that the hal callback arrives before
+ * SET_FUNCTIONS_TIMEOUT_MS expires. If the callback does not arrive
+ * within SET_FUNCTIONS_TIMEOUT_MS, UsbDeviceManager retries enabling
+ * default functions.
+ */
+ private static final int SET_FUNCTIONS_LEEWAY_MS = 500;
+
+ /**
+ * While switching functions, a disconnect is excpect as the usb gadget
+ * us torn down and brought back up. Wait for SET_FUNCTIONS_TIMEOUT_MS +
+ * ENUMERATION_TIME_OUT_MS before switching back to default fumctions when
+ * switching functions.
+ */
+ private static final int ENUMERATION_TIME_OUT_MS = 2000;
+
+ /**
+ * Command to start native service.
+ */
+ protected static final String CTL_START = "ctl.start";
+
+ /**
+ * Command to start native service.
+ */
+ protected static final String CTL_STOP = "ctl.stop";
+
+ /**
+ * Adb natvie daemon
+ */
+ protected static final String ADBD = "adbd";
+
+
+ UsbHandlerHal(Looper looper) {
+ super(looper);
+ try {
+ ServiceNotification serviceNotification = new ServiceNotification();
+
+ boolean ret = IServiceManager.getService()
+ .registerForNotifications("android.hardware.usb.gadget@1.0::IUsbGadget",
+ "", serviceNotification);
+ if (!ret) {
+ Slog.e(TAG, "Failed to register usb gadget service start notification");
+ return;
+ }
+
+ synchronized (mGadgetProxyLock) {
+ mGadgetProxy = IUsbGadget.getService(true);
+ mGadgetProxy.linkToDeath(new UsbGadgetDeathRecipient(),
+ USB_GADGET_HAL_DEATH_COOKIE);
+ mCurrentFunctions = UsbManager.USB_FUNCTION_NONE;
+ mGadgetProxy.getCurrentUsbFunctions(new UsbGadgetCallback());
+ mCurrentUsbFunctionsRequested = true;
+ }
+ String state = FileUtils.readTextFile(new File(STATE_PATH), 0, null).trim();
+ updateState(state);
+
+ /**
+ * Register observer to listen for settings changes.
+ */
+ mContentResolver.registerContentObserver(
+ Settings.Global.getUriFor(Settings.Global.ADB_ENABLED),
+ false, new AdbSettingsObserver());
+
+ /**
+ * Watch for USB configuration changes.
+ */
+ mUEventObserver.startObserving(USB_STATE_MATCH);
+ mUEventObserver.startObserving(ACCESSORY_START_MATCH);
+ } catch (NoSuchElementException e) {
+ Slog.e(TAG, "Usb gadget hal not found", e);
+ } catch (RemoteException e) {
+ Slog.e(TAG, "Usb Gadget hal not responding", e);
+ } catch (Exception e) {
+ Slog.e(TAG, "Error initializing UsbHandler", e);
+ }
+ }
+
+
+ final class UsbGadgetDeathRecipient implements HwBinder.DeathRecipient {
+ @Override
+ public void serviceDied(long cookie) {
+ if (cookie == USB_GADGET_HAL_DEATH_COOKIE) {
+ Slog.e(TAG, "Usb Gadget hal service died cookie: " + cookie);
+ synchronized (mGadgetProxyLock) {
+ mGadgetProxy = null;
+ }
+ }
+ }
+ }
+
+ final class ServiceNotification extends IServiceNotification.Stub {
+ @Override
+ public void onRegistration(String fqName, String name, boolean preexisting) {
+ Slog.i(TAG, "Usb gadget hal service started " + fqName + " " + name);
+ synchronized (mGadgetProxyLock) {
+ try {
+ mGadgetProxy = IUsbGadget.getService();
+ mGadgetProxy.linkToDeath(new UsbGadgetDeathRecipient(),
+ USB_GADGET_HAL_DEATH_COOKIE);
+ if (!mCurrentFunctionsApplied) {
+ setCurrentFunctions(mCurrentFunctions, mUsbDataUnlocked);
+ }
+ } catch (NoSuchElementException e) {
+ Slog.e(TAG, "Usb gadget hal not found", e);
+ } catch (RemoteException e) {
+ Slog.e(TAG, "Usb Gadget hal not responding", e);
+ }
+ }
+ }
+ }
+
+ @Override
+ public void handleMessage(Message msg) {
+ switch (msg.what) {
+ case MSG_SET_CHARGING_FUNCTIONS:
+ setEnabledFunctions(null, false, mUsbDataUnlocked);
+ break;
+ case MSG_SET_FUNCTIONS_TIMEOUT:
+ Slog.e(TAG, "Set functions timed out! no reply from usb hal");
+ if (msg.arg1 != 1) {
+ setEnabledFunctions(null, false, mUsbDataUnlocked);
+ }
+ break;
+ case MSG_GET_CURRENT_USB_FUNCTIONS:
+ Slog.e(TAG, "prcessing MSG_GET_CURRENT_USB_FUNCTIONS");
+ mCurrentUsbFunctionsReceived = true;
+
+ if (mCurrentUsbFunctionsRequested) {
+ Slog.e(TAG, "updating mCurrentFunctions");
+ mCurrentFunctions = functionListToString((Long) msg.obj);
+ Slog.e(TAG,
+ "mCurrentFunctions:" + mCurrentFunctions + "applied:" + msg.arg1);
+ mCurrentFunctionsApplied = msg.arg1 == 1;
+ }
+ finishBoot();
+ break;
+ case MSG_FUNCTION_SWITCH_TIMEOUT:
+ /**
+ * Dont force to default when the configuration is already set to default.
+ */
+ if (msg.arg1 != 1) {
+ setEnabledFunctions(null, !mAdbEnabled, false);
+ }
+ break;
+ default:
+ super.handleMessage(msg);
+ }
+ }
+
+ private class UsbGadgetCallback extends IUsbGadgetCallback.Stub {
+ int mRequest;
+ long mFunctions;
+ boolean mChargingFunctions;
+
+ UsbGadgetCallback() {
+ }
+
+ UsbGadgetCallback(int request, long functions,
+ boolean chargingFunctions) {
+ mRequest = request;
+ mFunctions = functions;
+ mChargingFunctions = chargingFunctions;
+ }
+
+ @Override
+ public void setCurrentUsbFunctionsCb(long functions,
+ int status) {
+ /**
+ * Callback called for a previous setCurrenUsbFunction
+ */
+ if ((mCurrentRequest != mRequest) || !hasMessages(MSG_SET_FUNCTIONS_TIMEOUT)
+ || (mFunctions != functions)) {
+ return;
+ }
+
+ removeMessages(MSG_SET_FUNCTIONS_TIMEOUT);
+ Slog.e(TAG, "notifyCurrentFunction request:" + mRequest + " status:" + status);
+ if (status == Status.SUCCESS) {
+ mCurrentFunctionsApplied = true;
+ } else if (!mChargingFunctions) {
+ Slog.e(TAG, "Setting default fuctions");
+ sendEmptyMessage(MSG_SET_CHARGING_FUNCTIONS);
+ }
+ }
+
+ @Override
+ public void getCurrentUsbFunctionsCb(long functions,
+ int status) {
+ sendMessage(MSG_GET_CURRENT_USB_FUNCTIONS, functions,
+ status == Status.FUNCTIONS_APPLIED);
+ }
+ }
+
+ private long stringToFunctionList(String config) {
+ long functionsMask = 0;
+ String[] functions = config.split(",");
+ for (int i = 0; i < functions.length; i++) {
+ switch (functions[i]) {
+ case "none":
+ functionsMask |= GadgetFunction.NONE;
+ break;
+ case "adb":
+ functionsMask |= GadgetFunction.ADB;
+ break;
+ case "mtp":
+ functionsMask |= GadgetFunction.MTP;
+ break;
+ case "ptp":
+ functionsMask |= GadgetFunction.PTP;
+ break;
+ case "midi":
+ functionsMask |= GadgetFunction.MIDI;
+ break;
+ case "accessory":
+ functionsMask |= GadgetFunction.ACCESSORY;
+ break;
+ case "rndis":
+ functionsMask |= GadgetFunction.RNDIS;
+ break;
+ }
+ }
+ return functionsMask;
+ }
+
+ private String functionListToString(Long functionList) {
+ StringJoiner functions = new StringJoiner(",");
+ if (functionList == GadgetFunction.NONE) {
+ functions.add("none");
+ return functions.toString();
+ }
+ if ((functionList & GadgetFunction.ADB) != 0) {
+ functions.add("adb");
+ }
+ if ((functionList & GadgetFunction.MTP) != 0) {
+ functions.add("mtp");
+ }
+ if ((functionList & GadgetFunction.PTP) != 0) {
+ functions.add("ptp");
+ }
+ if ((functionList & GadgetFunction.MIDI) != 0) {
+ functions.add("midi");
+ }
+ if ((functionList & GadgetFunction.ACCESSORY) != 0) {
+ functions.add("accessory");
+ }
+ if ((functionList & GadgetFunction.RNDIS) != 0) {
+ functions.add("rndis");
+ }
+ /**
+ * Remove the trailing comma.
+ */
+ return functions.toString();
+ }
+
+
+ private void setUsbConfig(String config, boolean chargingFunctions) {
+ Long functions = stringToFunctionList(config);
+ if (true) Slog.d(TAG, "setUsbConfig(" + config + ") request:" + ++mCurrentRequest);
+ /**
+ * Cancel any ongoing requests, if present.
+ */
+ removeMessages(MSG_FUNCTION_SWITCH_TIMEOUT);
+ removeMessages(MSG_SET_FUNCTIONS_TIMEOUT);
+ removeMessages(MSG_SET_CHARGING_FUNCTIONS);
+
+ synchronized (mGadgetProxyLock) {
+ if (mGadgetProxy == null) {
+ Slog.e(TAG, "setUsbConfig mGadgetProxy is null");
+ return;
+ }
+ try {
+ if ((functions & GadgetFunction.ADB) != 0) {
+ /**
+ * Start adbd if ADB function is included in the configuration.
+ */
+ SystemProperties.set(CTL_START, ADBD);
+ } else {
+ /**
+ * Stop adbd otherwise.
+ */
+ SystemProperties.set(CTL_STOP, ADBD);
+ }
+ UsbGadgetCallback usbGadgetCallback = new UsbGadgetCallback(mCurrentRequest,
+ functions, chargingFunctions);
+ mGadgetProxy.setCurrentUsbFunctions(functions, usbGadgetCallback,
+ SET_FUNCTIONS_TIMEOUT_MS - SET_FUNCTIONS_LEEWAY_MS);
+ sendMessageDelayed(MSG_SET_FUNCTIONS_TIMEOUT, chargingFunctions,
+ SET_FUNCTIONS_TIMEOUT_MS);
+ sendMessageDelayed(MSG_FUNCTION_SWITCH_TIMEOUT, chargingFunctions,
+ SET_FUNCTIONS_TIMEOUT_MS + ENUMERATION_TIME_OUT_MS);
+ if (DEBUG) Slog.d(TAG, "timeout message queued");
+ } catch (RemoteException e) {
+ Slog.e(TAG, "Remoteexception while calling setCurrentUsbFunctions", e);
+ }
+ }
+ }
+
+ @Override
+ protected void setEnabledFunctions(String functions, boolean forceRestart,
+ boolean usbDataUnlocked) {
+ if (DEBUG) {
+ Slog.d(TAG, "setEnabledFunctions functions=" + functions + ", "
+ + "forceRestart=" + forceRestart + ", usbDataUnlocked=" + usbDataUnlocked);
+ }
+
+ if (usbDataUnlocked != mUsbDataUnlocked) {
+ mUsbDataUnlocked = usbDataUnlocked;
+ updateUsbNotification(false);
+ forceRestart = true;
+ }
+
+ trySetEnabledFunctions(functions, forceRestart);
+ }
+
+ private void trySetEnabledFunctions(String functions, boolean forceRestart) {
+ boolean chargingFunctions = false;
+
+ if (functions == null || applyAdbFunction(functions)
+ .equals(UsbManager.USB_FUNCTION_NONE)) {
+ functions = getChargingFunctions();
+ chargingFunctions = true;
+ }
+ functions = applyAdbFunction(functions);
+
+ if (!mCurrentFunctions.equals(functions)
+ || !mCurrentFunctionsApplied
+ || forceRestart) {
+ Slog.i(TAG, "Setting USB config to " + functions);
+ mCurrentFunctions = functions;
+ mCurrentFunctionsApplied = false;
+ // set the flag to false as that would be stale value
+ mCurrentUsbFunctionsRequested = false;
+
+ // Set the new USB configuration.
+ setUsbConfig(mCurrentFunctions, chargingFunctions);
+
+ if (mBootCompleted
+ && (UsbManager.containsFunction(functions, UsbManager.USB_FUNCTION_MTP)
+ || UsbManager.containsFunction(functions, UsbManager.USB_FUNCTION_PTP))) {
+ // Start up dependent services.
+ updateUsbStateBroadcastIfNeeded(true);
+ }
+ }
+ }
}
/* returns the currently attached USB accessory */
@@ -1389,7 +1947,11 @@
return mHandler.getCurrentAccessory();
}
- /* opens the currently attached USB accessory */
+ /**
+ * opens the currently attached USB accessory.
+ *
+ * @param accessory accessory to be openened.
+ */
public ParcelFileDescriptor openAccessory(UsbAccessory accessory,
UsbUserSettingsManager settings) {
UsbAccessory currentAccessory = mHandler.getCurrentAccessory();
@@ -1406,20 +1968,32 @@
return nativeOpenAccessory();
}
+ /**
+ * Checks whether the function is present in the USB configuration.
+ *
+ * @param function function to be checked.
+ */
public boolean isFunctionEnabled(String function) {
- return UsbManager.containsFunction(SystemProperties.get(USB_CONFIG_PROPERTY), function);
+ return mHandler.isFunctionEnabled(function);
}
+ /**
+ * Adds function to the current USB configuration.
+ *
+ * @param functions name of the USB function, or null to restore the default function.
+ * @param usbDataUnlocked whether user data is accessible.
+ */
public void setCurrentFunctions(String functions, boolean usbDataUnlocked) {
if (DEBUG) {
- Slog.d(TAG, "setCurrentFunctions(" + functions + ", " +
- usbDataUnlocked + ")");
+ Slog.d(TAG, "setCurrentFunctions(" + functions + ", "
+ + usbDataUnlocked + ")");
}
mHandler.sendMessage(MSG_SET_CURRENT_FUNCTIONS, functions, usbDataUnlocked);
}
/**
* Sets the functions which are set when the screen is unlocked.
+ *
* @param functions Functions to set.
*/
public void setScreenUnlockedFunctions(String functions) {
@@ -1429,101 +2003,6 @@
mHandler.sendMessage(MSG_SET_SCREEN_UNLOCKED_FUNCTIONS, functions);
}
- private void readOemUsbOverrideConfig() {
- String[] configList = mContext.getResources().getStringArray(
- com.android.internal.R.array.config_oemUsbModeOverride);
-
- if (configList != null) {
- for (String config : configList) {
- String[] items = config.split(":");
- if (items.length == 3 || items.length == 4) {
- if (mOemModeMap == null) {
- mOemModeMap = new HashMap<>();
- }
- HashMap<String, Pair<String, String>> overrideMap
- = mOemModeMap.get(items[0]);
- if (overrideMap == null) {
- overrideMap = new HashMap<>();
- mOemModeMap.put(items[0], overrideMap);
- }
-
- // Favoring the first combination if duplicate exists
- if (!overrideMap.containsKey(items[1])) {
- if (items.length == 3) {
- overrideMap.put(items[1], new Pair<>(items[2], ""));
- } else {
- overrideMap.put(items[1], new Pair<>(items[2], items[3]));
- }
- }
- }
- }
- }
- }
-
- private String applyOemOverrideFunction(String usbFunctions) {
- if ((usbFunctions == null) || (mOemModeMap == null)) {
- return usbFunctions;
- }
-
- String bootMode = SystemProperties.get(BOOT_MODE_PROPERTY, "unknown");
- Slog.d(TAG, "applyOemOverride usbfunctions=" + usbFunctions + " bootmode=" + bootMode);
-
- Map<String, Pair<String, String>> overridesMap =
- mOemModeMap.get(bootMode);
- // Check to ensure that the oem is not overriding in the normal
- // boot mode
- if (overridesMap != null && !(bootMode.equals(NORMAL_BOOT) ||
- bootMode.equals("unknown"))) {
- Pair<String, String> overrideFunctions =
- overridesMap.get(usbFunctions);
- if (overrideFunctions != null) {
- Slog.d(TAG, "OEM USB override: " + usbFunctions
- + " ==> " + overrideFunctions.first
- + " persist across reboot "
- + overrideFunctions.second);
- if (!overrideFunctions.second.equals("")) {
- String newFunction;
- if (mAdbEnabled) {
- newFunction = UsbManager.addFunction(overrideFunctions.second,
- UsbManager.USB_FUNCTION_ADB);
- } else {
- newFunction = overrideFunctions.second;
- }
- Slog.d(TAG, "OEM USB override persisting: " + newFunction + "in prop: "
- + UsbDeviceManager.getPersistProp(false));
- SystemProperties.set(UsbDeviceManager.getPersistProp(false),
- newFunction);
- }
- return overrideFunctions.first;
- } else if (mAdbEnabled) {
- String newFunction = UsbManager.addFunction(UsbManager.USB_FUNCTION_NONE,
- UsbManager.USB_FUNCTION_ADB);
- SystemProperties.set(UsbDeviceManager.getPersistProp(false),
- newFunction);
- } else {
- SystemProperties.set(UsbDeviceManager.getPersistProp(false),
- UsbManager.USB_FUNCTION_NONE);
- }
- }
- // return passed in functions as is.
- return usbFunctions;
- }
-
- public static String getPersistProp(boolean functions) {
- String bootMode = SystemProperties.get(BOOT_MODE_PROPERTY, "unknown");
- String persistProp = USB_PERSISTENT_CONFIG_PROPERTY;
- if (!(bootMode.equals(NORMAL_BOOT) || bootMode.equals("unknown"))) {
- if (functions) {
- persistProp = "persist.sys.usb." + bootMode + ".func";
- } else {
- persistProp = "persist.sys.usb." + bootMode + ".config";
- }
- }
-
- return persistProp;
- }
-
-
public void allowUsbDebugging(boolean alwaysAllow, String publicKey) {
if (mDebuggingManager != null) {
mDebuggingManager.allowUsbDebugging(alwaysAllow, publicKey);
diff --git a/telephony/java/android/telephony/euicc/EuiccCardManager.java b/telephony/java/android/telephony/euicc/EuiccCardManager.java
index 88bae33..a1a6a5a 100644
--- a/telephony/java/android/telephony/euicc/EuiccCardManager.java
+++ b/telephony/java/android/telephony/euicc/EuiccCardManager.java
@@ -110,6 +110,9 @@
/** Result code of execution with no error. */
public static final int RESULT_OK = 0;
+ /** Result code of an unknown error. */
+ public static final int RESULT_UNKNOWN_ERROR = -1;
+
/**
* Callback to receive the result of an eUICC card API.
*