Merge "Schematize Car system properties"
diff --git a/Android.bp b/Android.bp
index 2ae7d6c..0210bb3 100644
--- a/Android.bp
+++ b/Android.bp
@@ -265,6 +265,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/permission/IRuntimePermissionPresenter.aidl",
"core/java/android/rolecontrollerservice/IRoleControllerService.aidl",
":keystore_aidl",
"core/java/android/security/keymaster/IKeyAttestationApplicationIdProvider.aidl",
@@ -442,7 +443,6 @@
"location/java/android/location/IGeocodeProvider.aidl",
"location/java/android/location/IGeofenceProvider.aidl",
"location/java/android/location/IGnssStatusListener.aidl",
- "location/java/android/location/IGnssStatusProvider.aidl",
"location/java/android/location/IGnssMeasurementsListener.aidl",
"location/java/android/location/IGnssNavigationMessageListener.aidl",
"location/java/android/location/ILocationListener.aidl",
@@ -451,6 +451,7 @@
"location/java/android/location/IGpsGeofenceHardware.aidl",
"location/java/android/location/INetInitiatedListener.aidl",
"location/java/com/android/internal/location/ILocationProvider.aidl",
+ "location/java/com/android/internal/location/ILocationProviderManager.aidl",
"media/java/android/media/IAudioFocusDispatcher.aidl",
"media/java/android/media/IAudioRoutesObserver.aidl",
"media/java/android/media/IAudioService.aidl",
@@ -633,7 +634,6 @@
":libupdate_engine_aidl",
":storaged_aidl",
- ":netd_aidl",
":vold_aidl",
":installd_aidl",
":dumpstate_aidl",
@@ -1617,6 +1617,7 @@
],
dex_mapping_filename: "dex-mapping.txt",
args: metalava_framework_docs_args +
+ " --hide ReferencesHidden " +
" --show-unannotated " +
" --show-annotation android.annotation.SystemApi " +
" --show-annotation android.annotation.TestApi "
diff --git a/api/current.txt b/api/current.txt
index 2ef4a39..931b9fa 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -644,6 +644,7 @@
field public static final int forceHasOverlappingRendering = 16844065; // 0x1010521
field public static final int foreground = 16843017; // 0x1010109
field public static final int foregroundGravity = 16843264; // 0x1010200
+ field public static final int foregroundServiceType = 16844191; // 0x101059f
field public static final int foregroundTint = 16843885; // 0x101046d
field public static final int foregroundTintMode = 16843886; // 0x101046e
field public static final int format = 16843013; // 0x1010105
@@ -6664,7 +6665,7 @@
method public void setDelegatedScopes(android.content.ComponentName, java.lang.String, java.util.List<java.lang.String>);
method public void setDeviceOwnerLockScreenInfo(android.content.ComponentName, java.lang.CharSequence);
method public void setEndUserSessionMessage(android.content.ComponentName, java.lang.CharSequence);
- method public void setGlobalPrivateDns(android.content.ComponentName, int, java.lang.String);
+ method public int setGlobalPrivateDns(android.content.ComponentName, int, java.lang.String);
method public void setGlobalSetting(android.content.ComponentName, java.lang.String, java.lang.String);
method public void setKeepUninstalledPackages(android.content.ComponentName, java.util.List<java.lang.String>);
method public boolean setKeyPairCertificate(android.content.ComponentName, java.lang.String, java.util.List<java.security.cert.Certificate>, boolean);
@@ -6845,6 +6846,9 @@
field public static final int PRIVATE_DNS_MODE_OPPORTUNISTIC = 2; // 0x2
field public static final int PRIVATE_DNS_MODE_PROVIDER_HOSTNAME = 3; // 0x3
field public static final int PRIVATE_DNS_MODE_UNKNOWN = 0; // 0x0
+ field public static final int PRIVATE_DNS_SET_ERROR_FAILURE_SETTING = 2; // 0x2
+ field public static final int PRIVATE_DNS_SET_ERROR_HOST_NOT_SERVING = 1; // 0x1
+ field public static final int PRIVATE_DNS_SET_SUCCESS = 0; // 0x0
field public static final int RESET_PASSWORD_DO_NOT_ASK_CREDENTIALS_ON_BOOT = 2; // 0x2
field public static final int RESET_PASSWORD_REQUIRE_ENTRY = 1; // 0x1
field public static final int SKIP_SETUP_WIZARD = 1; // 0x1
@@ -9227,11 +9231,31 @@
field public static final android.os.Parcelable.Creator<android.content.ComponentName> CREATOR;
}
- public abstract class ContentProvider implements android.content.ComponentCallbacks2 {
+ public abstract interface ContentInterface {
+ method public abstract android.content.ContentProviderResult[] applyBatch(java.lang.String, java.util.ArrayList<android.content.ContentProviderOperation>) throws android.content.OperationApplicationException, android.os.RemoteException;
+ method public abstract int bulkInsert(android.net.Uri, android.content.ContentValues[]) throws android.os.RemoteException;
+ method public abstract android.os.Bundle call(java.lang.String, java.lang.String, java.lang.String, android.os.Bundle) throws android.os.RemoteException;
+ method public abstract android.net.Uri canonicalize(android.net.Uri) throws android.os.RemoteException;
+ method public abstract int delete(android.net.Uri, java.lang.String, java.lang.String[]) throws android.os.RemoteException;
+ method public abstract java.lang.String[] getStreamTypes(android.net.Uri, java.lang.String) throws android.os.RemoteException;
+ method public abstract java.lang.String getType(android.net.Uri) throws android.os.RemoteException;
+ method public abstract android.net.Uri insert(android.net.Uri, android.content.ContentValues) throws android.os.RemoteException;
+ method public abstract android.content.res.AssetFileDescriptor openAssetFile(android.net.Uri, java.lang.String, android.os.CancellationSignal) throws java.io.FileNotFoundException, android.os.RemoteException;
+ method public abstract android.os.ParcelFileDescriptor openFile(android.net.Uri, java.lang.String, android.os.CancellationSignal) throws java.io.FileNotFoundException, android.os.RemoteException;
+ method public abstract android.content.res.AssetFileDescriptor openTypedAssetFile(android.net.Uri, java.lang.String, android.os.Bundle, android.os.CancellationSignal) throws java.io.FileNotFoundException, android.os.RemoteException;
+ method public abstract android.database.Cursor query(android.net.Uri, java.lang.String[], android.os.Bundle, android.os.CancellationSignal) throws android.os.RemoteException;
+ method public abstract boolean refresh(android.net.Uri, android.os.Bundle, android.os.CancellationSignal) throws android.os.RemoteException;
+ method public abstract android.net.Uri uncanonicalize(android.net.Uri) throws android.os.RemoteException;
+ method public abstract int update(android.net.Uri, android.content.ContentValues, java.lang.String, java.lang.String[]) throws android.os.RemoteException;
+ }
+
+ public abstract class ContentProvider implements android.content.ComponentCallbacks2 android.content.ContentInterface {
ctor public ContentProvider();
+ method public android.content.ContentProviderResult[] applyBatch(java.lang.String, java.util.ArrayList<android.content.ContentProviderOperation>) throws android.content.OperationApplicationException;
method public android.content.ContentProviderResult[] applyBatch(java.util.ArrayList<android.content.ContentProviderOperation>) throws android.content.OperationApplicationException;
method public void attachInfo(android.content.Context, android.content.pm.ProviderInfo);
method public int bulkInsert(android.net.Uri, android.content.ContentValues[]);
+ method public android.os.Bundle call(java.lang.String, java.lang.String, java.lang.String, android.os.Bundle);
method public android.os.Bundle call(java.lang.String, java.lang.String, android.os.Bundle);
method public android.net.Uri canonicalize(android.net.Uri);
method public final android.content.ContentProvider.CallingIdentity clearCallingIdentity();
@@ -9278,10 +9302,12 @@
method public abstract void writeDataToPipe(android.os.ParcelFileDescriptor, android.net.Uri, java.lang.String, android.os.Bundle, T);
}
- public class ContentProviderClient implements java.lang.AutoCloseable {
+ public class ContentProviderClient implements java.lang.AutoCloseable android.content.ContentInterface {
method public android.content.ContentProviderResult[] applyBatch(java.util.ArrayList<android.content.ContentProviderOperation>) throws android.content.OperationApplicationException, android.os.RemoteException;
+ method public android.content.ContentProviderResult[] applyBatch(java.lang.String, java.util.ArrayList<android.content.ContentProviderOperation>) throws android.content.OperationApplicationException, android.os.RemoteException;
method public int bulkInsert(android.net.Uri, android.content.ContentValues[]) throws android.os.RemoteException;
method public android.os.Bundle call(java.lang.String, java.lang.String, android.os.Bundle) throws android.os.RemoteException;
+ method public android.os.Bundle call(java.lang.String, java.lang.String, java.lang.String, android.os.Bundle) throws android.os.RemoteException;
method public final android.net.Uri canonicalize(android.net.Uri) throws android.os.RemoteException;
method public void close();
method public static void closeQuietly(android.content.ContentProviderClient);
@@ -9294,6 +9320,7 @@
method public android.content.res.AssetFileDescriptor openAssetFile(android.net.Uri, java.lang.String, android.os.CancellationSignal) throws java.io.FileNotFoundException, android.os.RemoteException;
method public android.os.ParcelFileDescriptor openFile(android.net.Uri, java.lang.String) throws java.io.FileNotFoundException, android.os.RemoteException;
method public android.os.ParcelFileDescriptor openFile(android.net.Uri, java.lang.String, android.os.CancellationSignal) throws java.io.FileNotFoundException, android.os.RemoteException;
+ method public final android.content.res.AssetFileDescriptor openTypedAssetFile(android.net.Uri, java.lang.String, android.os.Bundle, android.os.CancellationSignal) throws java.io.FileNotFoundException, android.os.RemoteException;
method public final android.content.res.AssetFileDescriptor openTypedAssetFileDescriptor(android.net.Uri, java.lang.String, android.os.Bundle) throws java.io.FileNotFoundException, android.os.RemoteException;
method public final android.content.res.AssetFileDescriptor openTypedAssetFileDescriptor(android.net.Uri, java.lang.String, android.os.Bundle, android.os.CancellationSignal) throws java.io.FileNotFoundException, android.os.RemoteException;
method public android.database.Cursor query(android.net.Uri, java.lang.String[], java.lang.String, java.lang.String[], java.lang.String) throws android.os.RemoteException;
@@ -9358,7 +9385,7 @@
method public void setKeepUpdated(boolean);
}
- public abstract class ContentResolver {
+ public abstract class ContentResolver implements android.content.ContentInterface {
ctor public ContentResolver(android.content.Context);
method public final android.content.ContentProviderClient acquireContentProviderClient(android.net.Uri);
method public final android.content.ContentProviderClient acquireContentProviderClient(java.lang.String);
@@ -9369,6 +9396,7 @@
method public android.content.ContentProviderResult[] applyBatch(java.lang.String, java.util.ArrayList<android.content.ContentProviderOperation>) throws android.content.OperationApplicationException, android.os.RemoteException;
method public final int bulkInsert(android.net.Uri, android.content.ContentValues[]);
method public final android.os.Bundle call(android.net.Uri, java.lang.String, java.lang.String, android.os.Bundle);
+ method public final android.os.Bundle call(java.lang.String, java.lang.String, java.lang.String, android.os.Bundle);
method public deprecated void cancelSync(android.net.Uri);
method public static void cancelSync(android.accounts.Account, java.lang.String);
method public static void cancelSync(android.content.SyncRequest);
@@ -9392,13 +9420,16 @@
method public void notifyChange(android.net.Uri, android.database.ContentObserver);
method public void notifyChange(android.net.Uri, android.database.ContentObserver, boolean);
method public void notifyChange(android.net.Uri, android.database.ContentObserver, int);
+ method public final android.content.res.AssetFileDescriptor openAssetFile(android.net.Uri, java.lang.String, android.os.CancellationSignal) throws java.io.FileNotFoundException;
method public final android.content.res.AssetFileDescriptor openAssetFileDescriptor(android.net.Uri, java.lang.String) throws java.io.FileNotFoundException;
method public final android.content.res.AssetFileDescriptor openAssetFileDescriptor(android.net.Uri, java.lang.String, android.os.CancellationSignal) throws java.io.FileNotFoundException;
+ method public final android.os.ParcelFileDescriptor openFile(android.net.Uri, java.lang.String, android.os.CancellationSignal) throws java.io.FileNotFoundException;
method public final android.os.ParcelFileDescriptor openFileDescriptor(android.net.Uri, java.lang.String) throws java.io.FileNotFoundException;
method public final android.os.ParcelFileDescriptor openFileDescriptor(android.net.Uri, java.lang.String, android.os.CancellationSignal) throws java.io.FileNotFoundException;
method public final java.io.InputStream openInputStream(android.net.Uri) throws java.io.FileNotFoundException;
method public final java.io.OutputStream openOutputStream(android.net.Uri) throws java.io.FileNotFoundException;
method public final java.io.OutputStream openOutputStream(android.net.Uri, java.lang.String) throws java.io.FileNotFoundException;
+ method public final android.content.res.AssetFileDescriptor openTypedAssetFile(android.net.Uri, java.lang.String, android.os.Bundle, android.os.CancellationSignal) throws java.io.FileNotFoundException;
method public final android.content.res.AssetFileDescriptor openTypedAssetFileDescriptor(android.net.Uri, java.lang.String, android.os.Bundle) throws java.io.FileNotFoundException;
method public final android.content.res.AssetFileDescriptor openTypedAssetFileDescriptor(android.net.Uri, java.lang.String, android.os.Bundle, android.os.CancellationSignal) throws java.io.FileNotFoundException;
method public final android.database.Cursor query(android.net.Uri, java.lang.String[], java.lang.String, java.lang.String[], java.lang.String);
@@ -11479,6 +11510,7 @@
field public static final java.lang.String FEATURE_HIFI_SENSORS = "android.hardware.sensor.hifi_sensors";
field public static final java.lang.String FEATURE_HOME_SCREEN = "android.software.home_screen";
field public static final java.lang.String FEATURE_INPUT_METHODS = "android.software.input_methods";
+ field public static final java.lang.String FEATURE_IPSEC_TUNNELS = "android.software.ipsec_tunnels";
field public static final java.lang.String FEATURE_IRIS = "android.hardware.iris";
field public static final java.lang.String FEATURE_LEANBACK = "android.software.leanback";
field public static final java.lang.String FEATURE_LEANBACK_ONLY = "android.software.leanback_only";
@@ -11724,12 +11756,20 @@
ctor public ServiceInfo(android.content.pm.ServiceInfo);
method public int describeContents();
method public void dump(android.util.Printer, java.lang.String);
+ method public int getForegroundServiceType();
field public static final android.os.Parcelable.Creator<android.content.pm.ServiceInfo> CREATOR;
field public static final int FLAG_EXTERNAL_SERVICE = 4; // 0x4
field public static final int FLAG_ISOLATED_PROCESS = 2; // 0x2
field public static final int FLAG_SINGLE_USER = 1073741824; // 0x40000000
field public static final int FLAG_STOP_WITH_TASK = 1; // 0x1
field public static final int FLAG_USE_APP_ZYGOTE = 8; // 0x8
+ field public static final int FOREGROUND_SERVICE_TYPE_DEVICE_COMPANION = 5; // 0x5
+ field public static final int FOREGROUND_SERVICE_TYPE_LOCATION = 4; // 0x4
+ field public static final int FOREGROUND_SERVICE_TYPE_MEDIA_PLAY = 2; // 0x2
+ field public static final int FOREGROUND_SERVICE_TYPE_ONGOING_PROCESS = 6; // 0x6
+ field public static final int FOREGROUND_SERVICE_TYPE_PHONE_CALL = 3; // 0x3
+ field public static final int FOREGROUND_SERVICE_TYPE_SYNC = 1; // 0x1
+ field public static final int FOREGROUND_SERVICE_TYPE_UNSPECIFIED = 0; // 0x0
field public int flags;
field public java.lang.String permission;
}
@@ -22701,8 +22741,8 @@
method public boolean addNmeaListener(android.location.OnNmeaMessageListener, android.os.Handler);
method public void addProximityAlert(double, double, float, long, android.app.PendingIntent);
method public void addTestProvider(java.lang.String, boolean, boolean, boolean, boolean, boolean, boolean, boolean, int, int);
- method public void clearTestProviderEnabled(java.lang.String);
- method public void clearTestProviderLocation(java.lang.String);
+ method public deprecated void clearTestProviderEnabled(java.lang.String);
+ method public deprecated void clearTestProviderLocation(java.lang.String);
method public deprecated void clearTestProviderStatus(java.lang.String);
method public java.util.List<java.lang.String> getAllProviders();
method public java.lang.String getBestProvider(android.location.Criteria, boolean);
@@ -22914,6 +22954,7 @@
method public int getChannelIndexMask();
method public int getChannelMask();
method public int getEncoding();
+ method public int getFrameSizeInBytes();
method public int getSampleRate();
method public void writeToParcel(android.os.Parcel, int);
field public static final deprecated int CHANNEL_CONFIGURATION_DEFAULT = 1; // 0x1
@@ -23933,6 +23974,7 @@
field public static final deprecated int INFO_OUTPUT_BUFFERS_CHANGED = -3; // 0xfffffffd
field public static final int INFO_OUTPUT_FORMAT_CHANGED = -2; // 0xfffffffe
field public static final int INFO_TRY_AGAIN_LATER = -1; // 0xffffffff
+ field public static final java.lang.String PARAMETER_KEY_HDR10_PLUS_INFO = "hdr10-plus-info";
field public static final java.lang.String PARAMETER_KEY_REQUEST_SYNC_FRAME = "request-sync";
field public static final java.lang.String PARAMETER_KEY_SUSPEND = "drop-input-frames";
field public static final java.lang.String PARAMETER_KEY_VIDEO_BITRATE = "video-bitrate";
@@ -24206,6 +24248,7 @@
field public static final int HEVCProfileMain = 1; // 0x1
field public static final int HEVCProfileMain10 = 2; // 0x2
field public static final int HEVCProfileMain10HDR10 = 4096; // 0x1000
+ field public static final int HEVCProfileMain10HDR10Plus = 8192; // 0x2000
field public static final int HEVCProfileMainStill = 4; // 0x4
field public static final int MPEG2LevelH14 = 2; // 0x2
field public static final int MPEG2LevelHL = 3; // 0x3
@@ -24267,8 +24310,10 @@
field public static final int VP9Profile1 = 2; // 0x2
field public static final int VP9Profile2 = 4; // 0x4
field public static final int VP9Profile2HDR = 4096; // 0x1000
+ field public static final int VP9Profile2HDR10Plus = 16384; // 0x4000
field public static final int VP9Profile3 = 8; // 0x8
field public static final int VP9Profile3HDR = 8192; // 0x2000
+ field public static final int VP9Profile3HDR10Plus = 32768; // 0x8000
field public int level;
field public int profile;
}
@@ -24667,6 +24712,7 @@
field public static final java.lang.String KEY_FRAME_RATE = "frame-rate";
field public static final java.lang.String KEY_GRID_COLUMNS = "grid-cols";
field public static final java.lang.String KEY_GRID_ROWS = "grid-rows";
+ field public static final java.lang.String KEY_HDR10_PLUS_INFO = "hdr10-plus-info";
field public static final java.lang.String KEY_HDR_STATIC_INFO = "hdr-static-info";
field public static final java.lang.String KEY_HEIGHT = "height";
field public static final java.lang.String KEY_INTRA_REFRESH_PERIOD = "intra-refresh-period";
@@ -28340,6 +28386,7 @@
method public int describeContents();
method public int getLinkDownstreamBandwidthKbps();
method public int getLinkUpstreamBandwidthKbps();
+ method public android.net.TransportInfo getTransportInfo();
method public boolean hasCapability(int);
method public boolean hasTransport(int);
method public void writeToParcel(android.os.Parcel, int);
@@ -28548,6 +28595,9 @@
field public static final int UNSUPPORTED = -1; // 0xffffffff
}
+ public abstract interface TransportInfo {
+ }
+
public abstract class Uri implements java.lang.Comparable android.os.Parcelable {
method public abstract android.net.Uri.Builder buildUpon();
method public int compareTo(android.net.Uri);
@@ -28583,6 +28633,7 @@
method public abstract boolean isRelative();
method public android.net.Uri normalizeScheme();
method public static android.net.Uri parse(java.lang.String);
+ method public java.lang.String toSafeString();
method public abstract java.lang.String toString();
method public static android.net.Uri withAppendedPath(android.net.Uri, java.lang.String);
method public static void writeToParcel(android.os.Parcel, android.net.Uri);
@@ -35999,6 +36050,7 @@
field public static final java.lang.String CALENDAR_LOCATION = "calendar_location";
field public static final android.net.Uri CONTENT_URI;
field public static final java.lang.String DEFAULT_SORT_ORDER = "calendar_displayName";
+ field public static final android.net.Uri ENTERPRISE_CONTENT_URI;
field public static final java.lang.String NAME = "name";
}
@@ -36027,6 +36079,7 @@
public static final class CalendarContract.Events implements android.provider.BaseColumns android.provider.CalendarContract.CalendarColumns android.provider.CalendarContract.EventsColumns android.provider.CalendarContract.SyncColumns {
field public static final android.net.Uri CONTENT_EXCEPTION_URI;
field public static final android.net.Uri CONTENT_URI;
+ field public static final android.net.Uri ENTERPRISE_CONTENT_URI;
}
protected static abstract interface CalendarContract.EventsColumns {
@@ -36118,6 +36171,10 @@
field public static final java.lang.String END = "end";
field public static final java.lang.String END_DAY = "endDay";
field public static final java.lang.String END_MINUTE = "endMinute";
+ field public static final android.net.Uri ENTERPRISE_CONTENT_BY_DAY_URI;
+ field public static final android.net.Uri ENTERPRISE_CONTENT_SEARCH_BY_DAY_URI;
+ field public static final android.net.Uri ENTERPRISE_CONTENT_SEARCH_URI;
+ field public static final android.net.Uri ENTERPRISE_CONTENT_URI;
field public static final java.lang.String EVENT_ID = "event_id";
field public static final java.lang.String START_DAY = "startDay";
field public static final java.lang.String START_MINUTE = "startMinute";
@@ -37363,26 +37420,26 @@
method public static android.net.Uri buildRootsUri(java.lang.String);
method public static android.net.Uri buildSearchDocumentsUri(java.lang.String, java.lang.String, java.lang.String);
method public static android.net.Uri buildTreeDocumentUri(java.lang.String, java.lang.String);
- method public static android.net.Uri copyDocument(android.content.ContentResolver, android.net.Uri, android.net.Uri) throws java.io.FileNotFoundException;
- method public static android.net.Uri createDocument(android.content.ContentResolver, android.net.Uri, java.lang.String, java.lang.String) throws java.io.FileNotFoundException;
- method public static android.content.IntentSender createWebLinkIntent(android.content.ContentResolver, android.net.Uri, android.os.Bundle) throws java.io.FileNotFoundException;
- method public static boolean deleteDocument(android.content.ContentResolver, android.net.Uri) throws java.io.FileNotFoundException;
- method public static void ejectRoot(android.content.ContentResolver, android.net.Uri);
- method public static android.provider.DocumentsContract.Path findDocumentPath(android.content.ContentResolver, android.net.Uri) throws java.io.FileNotFoundException;
+ method public static android.net.Uri copyDocument(android.content.ContentInterface, android.net.Uri, android.net.Uri) throws java.io.FileNotFoundException;
+ method public static android.net.Uri createDocument(android.content.ContentInterface, android.net.Uri, java.lang.String, java.lang.String) throws java.io.FileNotFoundException;
+ method public static android.content.IntentSender createWebLinkIntent(android.content.ContentInterface, android.net.Uri, android.os.Bundle) throws java.io.FileNotFoundException;
+ method public static boolean deleteDocument(android.content.ContentInterface, android.net.Uri) throws java.io.FileNotFoundException;
+ method public static void ejectRoot(android.content.ContentInterface, android.net.Uri);
+ method public static android.provider.DocumentsContract.Path findDocumentPath(android.content.ContentInterface, android.net.Uri) throws java.io.FileNotFoundException;
method public static java.lang.String getDocumentId(android.net.Uri);
- method public static android.os.Bundle getDocumentMetadata(android.content.ContentResolver, android.net.Uri) throws java.io.FileNotFoundException;
- method public static android.graphics.Bitmap getDocumentThumbnail(android.content.ContentResolver, android.net.Uri, android.graphics.Point, android.os.CancellationSignal) throws java.io.FileNotFoundException;
+ method public static android.os.Bundle getDocumentMetadata(android.content.ContentInterface, android.net.Uri) throws java.io.FileNotFoundException;
+ method public static android.graphics.Bitmap getDocumentThumbnail(android.content.ContentInterface, android.net.Uri, android.graphics.Point, android.os.CancellationSignal) throws java.io.FileNotFoundException;
method public static java.lang.String getRootId(android.net.Uri);
method public static java.lang.String getSearchDocumentsQuery(android.net.Uri);
method public static java.lang.String getTreeDocumentId(android.net.Uri);
- method public static boolean isChildDocument(android.content.ContentResolver, android.net.Uri, android.net.Uri) throws java.io.FileNotFoundException;
+ method public static boolean isChildDocument(android.content.ContentInterface, android.net.Uri, android.net.Uri) throws java.io.FileNotFoundException;
method public static boolean isDocumentUri(android.content.Context, android.net.Uri);
method public static boolean isRootUri(android.content.Context, android.net.Uri);
method public static boolean isRootsUri(android.content.Context, android.net.Uri);
method public static boolean isTreeUri(android.net.Uri);
- method public static android.net.Uri moveDocument(android.content.ContentResolver, android.net.Uri, android.net.Uri, android.net.Uri) throws java.io.FileNotFoundException;
- method public static boolean removeDocument(android.content.ContentResolver, android.net.Uri, android.net.Uri) throws java.io.FileNotFoundException;
- method public static android.net.Uri renameDocument(android.content.ContentResolver, android.net.Uri, java.lang.String) throws java.io.FileNotFoundException;
+ method public static android.net.Uri moveDocument(android.content.ContentInterface, android.net.Uri, android.net.Uri, android.net.Uri) throws java.io.FileNotFoundException;
+ method public static boolean removeDocument(android.content.ContentInterface, android.net.Uri, android.net.Uri) throws java.io.FileNotFoundException;
+ method public static android.net.Uri renameDocument(android.content.ContentInterface, android.net.Uri, java.lang.String) throws java.io.FileNotFoundException;
field public static final java.lang.String ACTION_DOCUMENT_SETTINGS = "android.provider.action.DOCUMENT_SETTINGS";
field public static final java.lang.String EXTRA_ERROR = "error";
field public static final java.lang.String EXTRA_EXCLUDE_SELF = "android.provider.extra.EXCLUDE_SELF";
@@ -40411,6 +40468,7 @@
method public android.service.autofill.FillResponse.Builder setHeader(android.widget.RemoteViews);
method public android.service.autofill.FillResponse.Builder setIgnoredIds(android.view.autofill.AutofillId...);
method public android.service.autofill.FillResponse.Builder setSaveInfo(android.service.autofill.SaveInfo);
+ method public android.service.autofill.FillResponse.Builder setUserData(android.service.autofill.UserData);
}
public final class ImageTransformation implements android.os.Parcelable android.service.autofill.Transformation {
@@ -43729,10 +43787,10 @@
method public static java.lang.String getStrippedReversed(java.lang.String);
method public static final boolean is12Key(char);
method public static final boolean isDialable(char);
- method public static boolean isEmergencyNumber(java.lang.String);
+ method public static deprecated boolean isEmergencyNumber(java.lang.String);
method public static boolean isGlobalPhoneNumber(java.lang.String);
method public static boolean isISODigit(char);
- method public static boolean isLocalEmergencyNumber(android.content.Context, java.lang.String);
+ method public static deprecated boolean isLocalEmergencyNumber(android.content.Context, java.lang.String);
method public static final boolean isNonSeparator(char);
method public static final boolean isReallyDialable(char);
method public static final boolean isStartsPostDial(char);
@@ -44440,11 +44498,13 @@
method public java.util.List<java.lang.Integer> getEmergencyNumberSources();
method public java.util.List<java.lang.Integer> getEmergencyServiceCategories();
method public int getEmergencyServiceCategoryBitmask();
+ method public java.lang.String getMnc();
method public java.lang.String getNumber();
method public boolean isFromSources(int);
method public boolean isInEmergencyServiceCategories(int);
method public void writeToParcel(android.os.Parcel, int);
field public static final android.os.Parcelable.Creator<android.telephony.emergency.EmergencyNumber> CREATOR;
+ field public static final int EMERGENCY_NUMBER_SOURCE_DATABASE = 16; // 0x10
field public static final int EMERGENCY_NUMBER_SOURCE_DEFAULT = 8; // 0x8
field public static final int EMERGENCY_NUMBER_SOURCE_MODEM_CONFIG = 4; // 0x4
field public static final int EMERGENCY_NUMBER_SOURCE_NETWORK_SIGNALING = 1; // 0x1
@@ -52427,6 +52487,7 @@
public static final class ConversationActions.Request implements android.os.Parcelable {
method public int describeContents();
+ method public java.lang.String getCallingPackageName();
method public java.util.List<android.view.textclassifier.ConversationActions.Message> getConversation();
method public java.util.List<java.lang.String> getHints();
method public int getMaxSuggestions();
@@ -52540,6 +52601,7 @@
public static final class TextClassification.Request implements android.os.Parcelable {
method public int describeContents();
+ method public java.lang.String getCallingPackageName();
method public android.os.LocaleList getDefaultLocales();
method public int getEndIndex();
method public android.os.Bundle getExtras();
@@ -52657,6 +52719,7 @@
public static final class TextLanguage.Request implements android.os.Parcelable {
method public int describeContents();
+ method public java.lang.String getCallingPackageName();
method public android.os.Bundle getExtras();
method public java.lang.CharSequence getText();
method public void writeToParcel(android.os.Parcel, int);
@@ -52688,6 +52751,7 @@
public static final class TextLinks.Builder {
ctor public TextLinks.Builder(java.lang.String);
method public android.view.textclassifier.TextLinks.Builder addLink(int, int, java.util.Map<java.lang.String, java.lang.Float>);
+ method public android.view.textclassifier.TextLinks.Builder addLink(int, int, java.util.Map<java.lang.String, java.lang.Float>, android.os.Bundle);
method public android.view.textclassifier.TextLinks build();
method public android.view.textclassifier.TextLinks.Builder clearTextLinks();
method public android.view.textclassifier.TextLinks.Builder setExtras(android.os.Bundle);
@@ -52695,6 +52759,7 @@
public static final class TextLinks.Request implements android.os.Parcelable {
method public int describeContents();
+ method public java.lang.String getCallingPackageName();
method public android.os.LocaleList getDefaultLocales();
method public android.view.textclassifier.TextClassifier.EntityConfig getEntityConfig();
method public android.os.Bundle getExtras();
@@ -52717,6 +52782,7 @@
method public int getEnd();
method public java.lang.String getEntity(int);
method public int getEntityCount();
+ method public android.os.Bundle getExtras();
method public int getStart();
method public void writeToParcel(android.os.Parcel, int);
field public static final android.os.Parcelable.Creator<android.view.textclassifier.TextLinks.TextLink> CREATOR;
@@ -52751,6 +52817,7 @@
public static final class TextSelection.Request implements android.os.Parcelable {
method public int describeContents();
+ method public java.lang.String getCallingPackageName();
method public android.os.LocaleList getDefaultLocales();
method public int getEndIndex();
method public android.os.Bundle getExtras();
@@ -53251,7 +53318,7 @@
method public abstract boolean getDomStorageEnabled();
method public abstract java.lang.String getFantasyFontFamily();
method public abstract java.lang.String getFixedFontFamily();
- method public abstract int getForceDarkMode();
+ method public int getForceDarkMode();
method public abstract boolean getJavaScriptCanOpenWindowsAutomatically();
method public abstract boolean getJavaScriptEnabled();
method public abstract android.webkit.WebSettings.LayoutAlgorithm getLayoutAlgorithm();
@@ -53298,7 +53365,7 @@
method public abstract deprecated void setEnableSmoothTransition(boolean);
method public abstract void setFantasyFontFamily(java.lang.String);
method public abstract void setFixedFontFamily(java.lang.String);
- method public abstract void setForceDarkMode(int);
+ method public void setForceDarkMode(int);
method public abstract deprecated void setGeolocationDatabasePath(java.lang.String);
method public abstract void setGeolocationEnabled(boolean);
method public abstract void setJavaScriptCanOpenWindowsAutomatically(boolean);
diff --git a/api/system-current.txt b/api/system-current.txt
index a37da64..29089b3 100644
--- a/api/system-current.txt
+++ b/api/system-current.txt
@@ -7,6 +7,7 @@
field public static final java.lang.String ACCESS_CHECKIN_PROPERTIES = "android.permission.ACCESS_CHECKIN_PROPERTIES";
field public static final java.lang.String ACCESS_DRM_CERTIFICATES = "android.permission.ACCESS_DRM_CERTIFICATES";
field public static final deprecated java.lang.String ACCESS_FM_RADIO = "android.permission.ACCESS_FM_RADIO";
+ field public static final java.lang.String ACCESS_INSTANT_APPS = "android.permission.ACCESS_INSTANT_APPS";
field public static final java.lang.String ACCESS_MOCK_LOCATION = "android.permission.ACCESS_MOCK_LOCATION";
field public static final java.lang.String ACCESS_MTP = "android.permission.ACCESS_MTP";
field public static final java.lang.String ACCESS_NETWORK_CONDITIONS = "android.permission.ACCESS_NETWORK_CONDITIONS";
@@ -298,6 +299,7 @@
method public void killUid(int, java.lang.String);
method public void removeOnUidImportanceListener(android.app.ActivityManager.OnUidImportanceListener);
method public static void setPersistentVrThread(int);
+ method public boolean switchUser(android.os.UserHandle);
}
public static abstract interface ActivityManager.OnUidImportanceListener {
@@ -314,7 +316,6 @@
method public android.app.AppOpsManager.HistoricalPackageOps getHistoricalPackagesOps(int, java.lang.String, java.lang.String[], long, long);
method public static java.lang.String[] getOpStrs();
method public java.util.List<android.app.AppOpsManager.PackageOps> getOpsForPackage(int, java.lang.String, int[]);
- method public java.util.List<android.app.AppOpsManager.PackageOps> getPackagesForOpStrs(java.lang.String[]);
method public static int opToDefaultMode(java.lang.String);
method public static java.lang.String opToPermission(java.lang.String);
method public void setMode(java.lang.String, int, java.lang.String, int);
@@ -614,7 +615,12 @@
field public static final java.lang.String EXTRA_PROVISIONING_DEVICE_ADMIN_PACKAGE_LABEL = "android.app.extra.PROVISIONING_DEVICE_ADMIN_PACKAGE_LABEL";
field public static final java.lang.String EXTRA_PROVISIONING_ORGANIZATION_NAME = "android.app.extra.PROVISIONING_ORGANIZATION_NAME";
field public static final java.lang.String EXTRA_PROVISIONING_SUPPORT_URL = "android.app.extra.PROVISIONING_SUPPORT_URL";
+ field public static final java.lang.String EXTRA_PROVISIONING_TRIGGER = "android.app.extra.PROVISIONING_TRIGGER";
field public static final java.lang.String EXTRA_RESTRICTION = "android.app.extra.RESTRICTION";
+ field public static final int PROVISIONING_TRIGGER_CLOUD_ENROLLMENT = 1; // 0x1
+ field public static final int PROVISIONING_TRIGGER_PERSISTENT_DEVICE_OWNER = 3; // 0x3
+ field public static final int PROVISIONING_TRIGGER_QR_CODE = 2; // 0x2
+ field public static final int PROVISIONING_TRIGGER_UNSPECIFIED = 0; // 0x0
field public static final int STATE_USER_PROFILE_COMPLETE = 4; // 0x4
field public static final int STATE_USER_SETUP_COMPLETE = 2; // 0x2
field public static final int STATE_USER_SETUP_FINALIZED = 3; // 0x3
@@ -845,6 +851,8 @@
method public int restoreAll(long, android.app.backup.RestoreObserver);
method public int restorePackage(java.lang.String, android.app.backup.RestoreObserver, android.app.backup.BackupManagerMonitor);
method public int restorePackage(java.lang.String, android.app.backup.RestoreObserver);
+ method public int restoreSome(long, android.app.backup.RestoreObserver, android.app.backup.BackupManagerMonitor, java.lang.String[]);
+ method public int restoreSome(long, android.app.backup.RestoreObserver, java.lang.String[]);
}
public class RestoreSet implements android.os.Parcelable {
@@ -1031,6 +1039,10 @@
package android.content {
+ public class ContentProviderClient implements java.lang.AutoCloseable android.content.ContentInterface {
+ method public void setDetectNotResponding(long);
+ }
+
public abstract class Context {
method public boolean bindServiceAsUser(android.content.Intent, android.content.ServiceConnection, int, android.os.UserHandle);
method public abstract android.content.Context createCredentialProtectedStorageContext();
@@ -1241,6 +1253,7 @@
method public abstract java.util.List<android.content.pm.IntentFilterVerificationInfo> getIntentFilterVerifications(java.lang.String);
method public abstract int getIntentVerificationStatusAsUser(java.lang.String, int);
method public abstract int getPermissionFlags(java.lang.String, java.lang.String, android.os.UserHandle);
+ method public java.lang.String getWellbeingPackageName();
method public abstract void grantRuntimePermission(java.lang.String, java.lang.String, android.os.UserHandle);
method public abstract int installExistingPackage(java.lang.String) throws android.content.pm.PackageManager.NameNotFoundException;
method public abstract int installExistingPackage(java.lang.String, int) throws android.content.pm.PackageManager.NameNotFoundException;
@@ -1343,6 +1356,7 @@
field public static final int FLAG_REMOVED = 2; // 0x2
field public static final int PROTECTION_FLAG_OEM = 16384; // 0x4000
field public static final int PROTECTION_FLAG_SYSTEM_TEXT_CLASSIFIER = 65536; // 0x10000
+ field public static final int PROTECTION_FLAG_WELLBEING = 131072; // 0x20000
field public java.lang.String backgroundPermission;
field public int requestRes;
}
@@ -1387,7 +1401,7 @@
package android.content.pm.permission {
- public final class RuntimePermissionPresentationInfo implements android.os.Parcelable {
+ public final deprecated class RuntimePermissionPresentationInfo implements android.os.Parcelable {
ctor public RuntimePermissionPresentationInfo(java.lang.CharSequence, boolean, boolean);
method public int describeContents();
method public java.lang.CharSequence getLabel();
@@ -2920,6 +2934,13 @@
field public static final int RADIO_TUNER = 1998; // 0x7ce
}
+ public static class MediaTimestamp.Builder {
+ ctor public MediaTimestamp.Builder();
+ ctor public MediaTimestamp.Builder(android.media.MediaTimestamp);
+ method public android.media.MediaTimestamp build();
+ method public android.media.MediaTimestamp.Builder setMediaTimestamp(long, long, float);
+ }
+
public class PlayerProxy {
method public void pause();
method public void setPan(float);
@@ -2940,7 +2961,7 @@
ctor public TimedMetaData.Builder();
ctor public TimedMetaData.Builder(android.media.TimedMetaData);
method public android.media.TimedMetaData build();
- method public android.media.TimedMetaData.Builder setTimedMetaData(int, byte[]);
+ method public android.media.TimedMetaData.Builder setTimedMetaData(long, byte[]);
}
}
@@ -3030,7 +3051,6 @@
package android.media.session {
public final class MediaSessionManager {
- method public android.media.session.ISession createSession(android.media.session.MediaSession.CallbackStub, java.lang.String, int);
method public void setOnMediaKeyListener(android.media.session.MediaSessionManager.OnMediaKeyListener, android.os.Handler);
method public void setOnVolumeKeyLongPressListener(android.media.session.MediaSessionManager.OnVolumeKeyLongPressListener, android.os.Handler);
}
@@ -4318,6 +4338,7 @@
}
public class UserManager {
+ method public boolean canSwitchUsers();
method public void clearSeedAccountData();
method public android.os.UserHandle getProfileParent(android.os.UserHandle);
method public java.lang.String getSeedAccountName();
@@ -4333,6 +4354,7 @@
method public boolean isManagedProfile(int);
method public boolean isPrimaryUser();
method public boolean isRestrictedProfile();
+ method public boolean removeUser(android.os.UserHandle);
field public static final java.lang.String ACTION_USER_RESTRICTIONS_CHANGED = "android.os.action.USER_RESTRICTIONS_CHANGED";
field public static final deprecated java.lang.String DISALLOW_OEM_UNLOCK = "no_oem_unlock";
field public static final java.lang.String DISALLOW_RUN_IN_BACKGROUND = "no_run_in_background";
@@ -4392,11 +4414,30 @@
method public int getTargetSdk();
}
+ public final class RuntimePermissionPresentationInfo implements android.os.Parcelable {
+ ctor public RuntimePermissionPresentationInfo(java.lang.CharSequence, boolean, boolean);
+ method public int describeContents();
+ method public java.lang.CharSequence getLabel();
+ method public boolean isGranted();
+ method public boolean isStandard();
+ method public void writeToParcel(android.os.Parcel, int);
+ field public static final android.os.Parcelable.Creator<android.permission.RuntimePermissionPresentationInfo> CREATOR;
+ }
+
+ public abstract class RuntimePermissionPresenterService extends android.app.Service {
+ ctor public RuntimePermissionPresenterService();
+ method public final void attachBaseContext(android.content.Context);
+ method public final android.os.IBinder onBind(android.content.Intent);
+ method public abstract java.util.List<android.permission.RuntimePermissionPresentationInfo> onGetAppPermissions(java.lang.String);
+ method public abstract void onRevokeRuntimePermission(java.lang.String, java.lang.String);
+ field public static final java.lang.String SERVICE_INTERFACE = "android.permission.RuntimePermissionPresenterService";
+ }
+
}
package android.permissionpresenterservice {
- public abstract class RuntimePermissionPresenterService extends android.app.Service {
+ public abstract deprecated class RuntimePermissionPresenterService extends android.app.Service {
ctor public RuntimePermissionPresenterService();
method public final void attachBaseContext(android.content.Context);
method public final android.os.IBinder onBind(android.content.Intent);
@@ -4522,6 +4563,11 @@
field public static final int FLAG_REMOVABLE_USB = 524288; // 0x80000
}
+ public final class MediaStore {
+ method public static void deleteContributedMedia(android.content.Context, java.lang.String);
+ method public static long getContributedMediaSize(android.content.Context, java.lang.String);
+ }
+
public abstract class SearchIndexableData {
ctor public SearchIndexableData();
ctor public SearchIndexableData(android.content.Context);
@@ -5924,6 +5970,7 @@
method public int getVoiceActivationState();
method public boolean handlePinMmi(java.lang.String);
method public boolean handlePinMmiForSubscriber(int, java.lang.String);
+ method public boolean isCurrentPotentialEmergencyNumber(java.lang.String);
method public boolean isDataConnectivityPossible();
method public deprecated boolean isIdle();
method public deprecated boolean isOffhook();
diff --git a/api/test-current.txt b/api/test-current.txt
index 46cbb52..5bedc72 100644
--- a/api/test-current.txt
+++ b/api/test-current.txt
@@ -276,6 +276,23 @@
}
+package android.app.role {
+
+ public final class RoleManager {
+ method public void addRoleHolderAsUser(java.lang.String, java.lang.String, android.os.UserHandle, java.util.concurrent.Executor, android.app.role.RoleManagerCallback);
+ method public void clearRoleHoldersAsUser(java.lang.String, android.os.UserHandle, java.util.concurrent.Executor, android.app.role.RoleManagerCallback);
+ method public java.util.List<java.lang.String> getRoleHolders(java.lang.String);
+ method public java.util.List<java.lang.String> getRoleHoldersAsUser(java.lang.String, android.os.UserHandle);
+ method public void removeRoleHolderAsUser(java.lang.String, java.lang.String, android.os.UserHandle, java.util.concurrent.Executor, android.app.role.RoleManagerCallback);
+ }
+
+ public abstract interface RoleManagerCallback {
+ method public abstract void onFailure();
+ method public abstract void onSuccess();
+ }
+
+}
+
package android.app.usage {
public class NetworkStatsManager {
@@ -299,7 +316,11 @@
package android.content {
- public abstract class ContentResolver {
+ public class ContentProviderClient implements java.lang.AutoCloseable android.content.ContentInterface {
+ method public void setDetectNotResponding(long);
+ }
+
+ public abstract class ContentResolver implements android.content.ContentInterface {
method public static java.lang.String[] getSyncAdapterPackagesForAuthorityAsUser(java.lang.String, int);
}
@@ -353,6 +374,7 @@
public class PermissionInfo extends android.content.pm.PackageItemInfo implements android.os.Parcelable {
field public static final int PROTECTION_FLAG_SYSTEM_TEXT_CLASSIFIER = 65536; // 0x10000
field public static final int PROTECTION_FLAG_VENDOR_PRIVILEGED = 32768; // 0x8000
+ field public static final int PROTECTION_FLAG_WELLBEING = 131072; // 0x20000
field public java.lang.String backgroundPermission;
}
@@ -983,6 +1005,11 @@
field public static final android.net.Uri CORP_CONTENT_URI;
}
+ public final class MediaStore {
+ method public static void deleteContributedMedia(android.content.Context, java.lang.String);
+ method public static long getContributedMediaSize(android.content.Context, java.lang.String);
+ }
+
public final class Settings {
field public static final java.lang.String ACTION_ENTERPRISE_PRIVACY_SETTINGS = "android.settings.ENTERPRISE_PRIVACY_SETTINGS";
}
diff --git a/cmds/content/src/com/android/commands/content/Content.java b/cmds/content/src/com/android/commands/content/Content.java
index 52a2ab4..55dbc17 100644
--- a/cmds/content/src/com/android/commands/content/Content.java
+++ b/cmds/content/src/com/android/commands/content/Content.java
@@ -557,7 +557,7 @@
@Override
public void onExecute(IContentProvider provider) throws Exception {
- Bundle result = provider.call(null, mMethod, mArg, mExtras);
+ Bundle result = provider.call(null, mUri.getAuthority(), mMethod, mArg, mExtras);
if (result != null) {
result.size(); // unpack
}
diff --git a/cmds/device_config/Android.mk b/cmds/device_config/Android.mk
new file mode 100644
index 0000000..4041e01
--- /dev/null
+++ b/cmds/device_config/Android.mk
@@ -0,0 +1,10 @@
+# Copyright 2018 The Android Open Source Project
+#
+LOCAL_PATH:= $(call my-dir)
+
+include $(CLEAR_VARS)
+LOCAL_MODULE := device_config
+LOCAL_SRC_FILES := device_config
+LOCAL_MODULE_CLASS := EXECUTABLES
+LOCAL_MODULE_TAGS := optional
+include $(BUILD_PREBUILT)
diff --git a/cmds/device_config/device_config b/cmds/device_config/device_config
new file mode 100755
index 0000000..a949bd5
--- /dev/null
+++ b/cmds/device_config/device_config
@@ -0,0 +1,2 @@
+#!/system/bin/sh
+cmd device_config "$@"
diff --git a/cmds/statsd/src/atoms.proto b/cmds/statsd/src/atoms.proto
index 392d40a..78d8e29 100644
--- a/cmds/statsd/src/atoms.proto
+++ b/cmds/statsd/src/atoms.proto
@@ -30,6 +30,7 @@
import "frameworks/base/core/proto/android/server/location/enums.proto";
import "frameworks/base/core/proto/android/service/procstats_enum.proto";
import "frameworks/base/core/proto/android/stats/enums.proto";
+import "frameworks/base/core/proto/android/stats/docsui/docsui_enums.proto";
import "frameworks/base/core/proto/android/stats/launcher/launcher.proto";
import "frameworks/base/core/proto/android/telecomm/enums.proto";
import "frameworks/base/core/proto/android/telephony/enums.proto";
@@ -159,6 +160,15 @@
PhenotypeFlagStateChanged phenotype_flag_state_changed = 101;
BinaryPushStateChanged binary_push_state_changed = 102;
DevicePolicyEvent device_policy_event = 103;
+ DocsUIFileOperationCanceledReported docs_ui_file_op_canceled = 104;
+ DocsUIFileOperationCopyMoveModeReported docs_ui_file_op_copy_move_mode_reported = 105;
+ DocsUIFileOperationFailureReported docs_ui_file_op_failure = 106;
+ DocsUIFileOperationReported docs_ui_provider_file_op = 107;
+ DocsUIInvalidScopedAccessRequestReported docs_ui_invalid_scoped_access_request = 108;
+ DocsUILaunchReported docs_ui_launch_reported = 109;
+ DocsUIRootVisitedReported docs_ui_root_visited = 110;
+ DocsUIStartupMsReported docs_ui_startup_ms = 111;
+ DocsUIUserActionReported docs_ui_user_action_reported = 112;
}
// Pulled events will start at field 10000.
@@ -3467,3 +3477,103 @@
// A parameter specifying a list of package names, bundle extras or string parameters.
optional android.stats.devicepolicy.StringList string_list_value = 6 [(log_mode) = MODE_BYTES];
}
+
+/**
+ * Logs when DocumentsUI is started, and how. Call this when DocumentsUI first starts up.
+ *
+ * Logged from:
+ * package/app/DocumentsUI/src/com/android/documentsui/Metrics.java
+ */
+message DocsUILaunchReported {
+ optional android.stats.docsui.LaunchAction launch_action = 1;
+ optional bool has_initial_uri = 2;
+ optional android.stats.docsui.MimeType mime_type = 3;
+ optional android.stats.docsui.Root initial_root = 4;
+}
+
+/**
+ * Logs root/app visited event in file managers/picker. Call this when the user
+ * taps on root/app in hamburger menu.
+ *
+ * Logged from:
+ * package/app/DocumentsUI/src/com/android/documentsui/Metrics.java
+ */
+message DocsUIRootVisitedReported {
+ optional android.stats.docsui.ContextScope scope = 1;
+ optional android.stats.docsui.Root root = 2;
+}
+
+/**
+ * Logs file operation stats. Call this when a file operation has completed.
+ *
+ * Logged from:
+ * package/app/DocumentsUI/src/com/android/documentsui/Metrics.java
+ */
+message DocsUIFileOperationReported {
+ optional android.stats.docsui.Provider provider = 1;
+ optional android.stats.docsui.FileOperation file_op = 2;
+}
+
+/**
+ * Logs file operation stats. Call this when a copy/move operation has completed with a specific
+ * mode.
+ *
+ * Logged from:
+ * package/app/DocumentsUI/src/com/android/documentsui/Metrics.java
+ */
+message DocsUIFileOperationCopyMoveModeReported {
+ optional android.stats.docsui.FileOperation file_op = 1;
+ optional android.stats.docsui.CopyMoveOpMode mode = 2;
+}
+
+
+/**
+ * Logs file sub operation stats. Call this when a file operation has failed.
+ *
+ * Logged from:
+ * package/app/DocumentsUI/src/com/android/documentsui/Metrics.java
+ */
+message DocsUIFileOperationFailureReported {
+ optional android.stats.docsui.Authority authority = 1;
+ optional android.stats.docsui.SubFileOperation sub_op = 2;
+}
+
+/**
+* Logs the cancellation of a file operation. Call this when a job is canceled
+*
+* Logged from:
+* package/app/DocumentsUI/src/com/android/documentsui/Metrics.java
+*/
+message DocsUIFileOperationCanceledReported {
+ optional android.stats.docsui.FileOperation file_op = 1;
+}
+
+/**
+ * Logs startup time in milliseconds.
+ *
+ * Logged from:
+ * package/app/DocumentsUI/src/com/android/documentsui/Metrics.java
+ */
+message DocsUIStartupMsReported {
+ optional int32 startup_millis = 1;
+}
+
+/**
+ * Logs the action that was started by user.
+ *
+ * Logged from:
+ * package/app/DocumentsUI/src/com/android/documentsui/Metrics.java
+ */
+message DocsUIUserActionReported {
+ optional android.stats.docsui.UserAction action = 1;
+}
+
+/**
+ * Logs the invalid type when invalid scoped access is requested.
+ *
+ * Logged from:
+ * package/app/DocumentsUI/src/com/android/documentsui/ScopedAccessMetrics.java
+ */
+message DocsUIInvalidScopedAccessRequestReported {
+ optional android.stats.docsui.InvalidScopedAccess type = 1;
+}
\ No newline at end of file
diff --git a/cmds/statsd/src/external/StatsPuller.cpp b/cmds/statsd/src/external/StatsPuller.cpp
index f501574..7043d66 100644
--- a/cmds/statsd/src/external/StatsPuller.cpp
+++ b/cmds/statsd/src/external/StatsPuller.cpp
@@ -59,15 +59,21 @@
mLastPullTimeNs = elapsedTimeNs;
int64_t pullStartTimeNs = getElapsedRealtimeNs();
bool ret = PullInternal(&mCachedData);
+ if (!ret) {
+ mCachedData.clear();
+ return false;
+ }
StatsdStats::getInstance().notePullTime(mTagId, getElapsedRealtimeNs() - pullStartTimeNs);
for (const shared_ptr<LogEvent>& data : mCachedData) {
data->setElapsedTimestampNs(elapsedTimeNs);
data->setLogdWallClockTimestampNs(wallClockTimeNs);
}
- if (ret && mCachedData.size() > 0) {
+
+ if (mCachedData.size() > 0) {
mapAndMergeIsolatedUidsToHostUid(mCachedData, mUidMap, mTagId);
(*data) = mCachedData;
}
+
StatsdStats::getInstance().notePullDelay(mTagId, getElapsedRealtimeNs() - elapsedTimeNs);
return ret;
}
diff --git a/cmds/statsd/src/external/StatsPuller.h b/cmds/statsd/src/external/StatsPuller.h
index 22cb2f5..cafd797 100644
--- a/cmds/statsd/src/external/StatsPuller.h
+++ b/cmds/statsd/src/external/StatsPuller.h
@@ -39,6 +39,7 @@
// Pulls the data. The returned data will have elapsedTimeNs set as timeNs
// and will have wallClockTimeNs set as current wall clock time.
+ // Return true if the pull is successful.
bool Pull(const int64_t timeNs, std::vector<std::shared_ptr<LogEvent>>* data);
// Clear cache immediately
diff --git a/cmds/statsd/src/metrics/CountMetricProducer.cpp b/cmds/statsd/src/metrics/CountMetricProducer.cpp
index 5ca8814..14f2de0 100644
--- a/cmds/statsd/src/metrics/CountMetricProducer.cpp
+++ b/cmds/statsd/src/metrics/CountMetricProducer.cpp
@@ -49,6 +49,8 @@
const int FIELD_ID_BUCKET_SIZE = 10;
const int FIELD_ID_DIMENSION_PATH_IN_WHAT = 11;
const int FIELD_ID_DIMENSION_PATH_IN_CONDITION = 12;
+const int FIELD_ID_IS_ACTIVE = 13;
+
// for CountMetricDataWrapper
const int FIELD_ID_DATA = 1;
// for CountMetricData
@@ -151,10 +153,13 @@
} else {
flushIfNeededLocked(dumpTimeNs);
}
+ protoOutput->write(FIELD_TYPE_INT64 | FIELD_ID_ID, (long long)mMetricId);
+ protoOutput->write(FIELD_TYPE_INT64 | FIELD_ID_IS_ACTIVE, isActiveLocked());
+
+
if (mPastBuckets.empty()) {
return;
}
- protoOutput->write(FIELD_TYPE_INT64 | FIELD_ID_ID, (long long)mMetricId);
protoOutput->write(FIELD_TYPE_INT64 | FIELD_ID_TIME_BASE, (long long)mTimeBaseNs);
protoOutput->write(FIELD_TYPE_INT64 | FIELD_ID_BUCKET_SIZE, (long long)mBucketSizeNs);
diff --git a/cmds/statsd/src/metrics/DurationMetricProducer.cpp b/cmds/statsd/src/metrics/DurationMetricProducer.cpp
index 35deffe..7797bd9 100644
--- a/cmds/statsd/src/metrics/DurationMetricProducer.cpp
+++ b/cmds/statsd/src/metrics/DurationMetricProducer.cpp
@@ -48,6 +48,7 @@
const int FIELD_ID_BUCKET_SIZE = 10;
const int FIELD_ID_DIMENSION_PATH_IN_WHAT = 11;
const int FIELD_ID_DIMENSION_PATH_IN_CONDITION = 12;
+const int FIELD_ID_IS_ACTIVE = 13;
// for DurationMetricDataWrapper
const int FIELD_ID_DATA = 1;
// for DurationMetricData
@@ -461,12 +462,14 @@
} else {
flushIfNeededLocked(dumpTimeNs);
}
+ protoOutput->write(FIELD_TYPE_INT64 | FIELD_ID_ID, (long long)mMetricId);
+ protoOutput->write(FIELD_TYPE_INT64 | FIELD_ID_IS_ACTIVE, isActiveLocked());
+
if (mPastBuckets.empty()) {
VLOG(" Duration metric, empty return");
return;
}
- protoOutput->write(FIELD_TYPE_INT64 | FIELD_ID_ID, (long long)mMetricId);
protoOutput->write(FIELD_TYPE_INT64 | FIELD_ID_TIME_BASE, (long long)mTimeBaseNs);
protoOutput->write(FIELD_TYPE_INT64 | FIELD_ID_BUCKET_SIZE, (long long)mBucketSizeNs);
diff --git a/cmds/statsd/src/metrics/EventMetricProducer.cpp b/cmds/statsd/src/metrics/EventMetricProducer.cpp
index a18e406..31a4361 100644
--- a/cmds/statsd/src/metrics/EventMetricProducer.cpp
+++ b/cmds/statsd/src/metrics/EventMetricProducer.cpp
@@ -44,6 +44,7 @@
// for StatsLogReport
const int FIELD_ID_ID = 1;
const int FIELD_ID_EVENT_METRICS = 4;
+const int FIELD_ID_IS_ACTIVE = 13;
// for EventMetricDataWrapper
const int FIELD_ID_DATA = 1;
// for EventMetricData
@@ -108,10 +109,11 @@
const bool erase_data,
std::set<string> *str_set,
ProtoOutputStream* protoOutput) {
+ protoOutput->write(FIELD_TYPE_INT64 | FIELD_ID_ID, (long long)mMetricId);
+ protoOutput->write(FIELD_TYPE_INT64 | FIELD_ID_IS_ACTIVE, isActiveLocked());
if (mProto->size() <= 0) {
return;
}
- protoOutput->write(FIELD_TYPE_INT64 | FIELD_ID_ID, (long long)mMetricId);
size_t bufferSize = mProto->size();
VLOG("metric %lld dump report now... proto size: %zu ",
diff --git a/cmds/statsd/src/metrics/GaugeMetricProducer.cpp b/cmds/statsd/src/metrics/GaugeMetricProducer.cpp
index 3a34743..03e42ce 100644
--- a/cmds/statsd/src/metrics/GaugeMetricProducer.cpp
+++ b/cmds/statsd/src/metrics/GaugeMetricProducer.cpp
@@ -49,6 +49,7 @@
const int FIELD_ID_BUCKET_SIZE = 10;
const int FIELD_ID_DIMENSION_PATH_IN_WHAT = 11;
const int FIELD_ID_DIMENSION_PATH_IN_CONDITION = 12;
+const int FIELD_ID_IS_ACTIVE = 13;
// for GaugeMetricDataWrapper
const int FIELD_ID_DATA = 1;
const int FIELD_ID_SKIPPED = 2;
@@ -192,11 +193,13 @@
flushIfNeededLocked(dumpTimeNs);
}
+ protoOutput->write(FIELD_TYPE_INT64 | FIELD_ID_ID, (long long)mMetricId);
+ protoOutput->write(FIELD_TYPE_INT64 | FIELD_ID_IS_ACTIVE, isActiveLocked());
+
if (mPastBuckets.empty()) {
return;
}
- protoOutput->write(FIELD_TYPE_INT64 | FIELD_ID_ID, (long long)mMetricId);
protoOutput->write(FIELD_TYPE_INT64 | FIELD_ID_TIME_BASE, (long long)mTimeBaseNs);
protoOutput->write(FIELD_TYPE_INT64 | FIELD_ID_BUCKET_SIZE, (long long)mBucketSizeNs);
diff --git a/cmds/statsd/src/metrics/MetricProducer.h b/cmds/statsd/src/metrics/MetricProducer.h
index 127cbbd..09e2409 100644
--- a/cmds/statsd/src/metrics/MetricProducer.h
+++ b/cmds/statsd/src/metrics/MetricProducer.h
@@ -223,6 +223,10 @@
void activateLocked(int activationTrackerIndex, int64_t elapsedTimestampNs);
+ inline bool isActiveLocked() const {
+ return mIsActive;
+ }
+
/**
* Flushes the current bucket if the eventTime is after the current bucket's end time. This will
also flush the current partial bucket in memory.
diff --git a/cmds/statsd/src/metrics/ValueMetricProducer.cpp b/cmds/statsd/src/metrics/ValueMetricProducer.cpp
index a34df8aa..f25520b 100644
--- a/cmds/statsd/src/metrics/ValueMetricProducer.cpp
+++ b/cmds/statsd/src/metrics/ValueMetricProducer.cpp
@@ -52,6 +52,7 @@
const int FIELD_ID_BUCKET_SIZE = 10;
const int FIELD_ID_DIMENSION_PATH_IN_WHAT = 11;
const int FIELD_ID_DIMENSION_PATH_IN_CONDITION = 12;
+const int FIELD_ID_IS_ACTIVE = 13;
// for ValueMetricDataWrapper
const int FIELD_ID_DATA = 1;
const int FIELD_ID_SKIPPED = 2;
@@ -72,17 +73,15 @@
const int FIELD_ID_START_BUCKET_ELAPSED_MILLIS = 5;
const int FIELD_ID_END_BUCKET_ELAPSED_MILLIS = 6;
+const Value ZERO_LONG((int64_t)0);
+const Value ZERO_DOUBLE((int64_t)0);
+
// ValueMetric has a minimum bucket size of 10min so that we don't pull too frequently
-ValueMetricProducer::ValueMetricProducer(const ConfigKey& key,
- const ValueMetric& metric,
- const int conditionIndex,
- const sp<ConditionWizard>& conditionWizard,
- const int whatMatcherIndex,
- const sp<EventMatcherWizard>& matcherWizard,
- const int pullTagId,
- const int64_t timeBaseNs,
- const int64_t startTimeNs,
- const sp<StatsPullerManager>& pullerManager)
+ValueMetricProducer::ValueMetricProducer(
+ const ConfigKey& key, const ValueMetric& metric, const int conditionIndex,
+ const sp<ConditionWizard>& conditionWizard, const int whatMatcherIndex,
+ const sp<EventMatcherWizard>& matcherWizard, const int pullTagId, const int64_t timeBaseNs,
+ const int64_t startTimeNs, const sp<StatsPullerManager>& pullerManager)
: MetricProducer(metric.id(), key, timeBaseNs, conditionIndex, conditionWizard),
mWhatMatcherIndex(whatMatcherIndex),
mEventMatcherWizard(matcherWizard),
@@ -102,7 +101,9 @@
mAggregationType(metric.aggregation_type()),
mUseDiff(metric.has_use_diff() ? metric.use_diff() : (mIsPulled ? true : false)),
mValueDirection(metric.value_direction()),
- mSkipZeroDiffOutput(metric.skip_zero_diff_output()) {
+ mSkipZeroDiffOutput(metric.skip_zero_diff_output()),
+ mUseZeroDefaultBase(metric.use_zero_default_base()),
+ mHasGlobalBase(false) {
int64_t bucketSizeMills = 0;
if (metric.has_bucket()) {
bucketSizeMills = TimeUnitToBucketSizeInMillisGuardrailed(key.GetUid(), metric.bucket());
@@ -190,10 +191,12 @@
} else {
flushIfNeededLocked(dumpTimeNs);
}
+ protoOutput->write(FIELD_TYPE_INT64 | FIELD_ID_ID, (long long)mMetricId);
+ protoOutput->write(FIELD_TYPE_INT64 | FIELD_ID_IS_ACTIVE, isActiveLocked());
+
if (mPastBuckets.empty() && mSkippedBuckets.empty()) {
return;
}
- protoOutput->write(FIELD_TYPE_INT64 | FIELD_ID_ID, (long long)mMetricId);
protoOutput->write(FIELD_TYPE_INT64 | FIELD_ID_TIME_BASE, (long long)mTimeBaseNs);
protoOutput->write(FIELD_TYPE_INT64 | FIELD_ID_BUCKET_SIZE, (long long)mBucketSizeNs);
// Fills the dimension path if not slicing by ALL.
@@ -302,6 +305,15 @@
}
}
+void ValueMetricProducer::resetBase() {
+ for (auto& slice : mCurrentSlicedBucket) {
+ for (auto& interval : slice.second) {
+ interval.hasBase = false;
+ }
+ }
+ mHasGlobalBase = false;
+}
+
void ValueMetricProducer::onConditionChangedLocked(const bool condition,
const int64_t eventTimeNs) {
if (eventTimeNs < mCurrentBucketStartTimeNs) {
@@ -317,13 +329,10 @@
pullAndMatchEventsLocked(eventTimeNs);
}
- // when condition change from true to false, clear diff base
+ // when condition change from true to false, clear diff base but don't
+ // reset other counters as we may accumulate more value in the bucket.
if (mUseDiff && mCondition && !condition) {
- for (auto& slice : mCurrentSlicedBucket) {
- for (auto& interval : slice.second) {
- interval.hasBase = false;
- }
- }
+ resetBase();
}
mCondition = condition;
@@ -332,15 +341,17 @@
void ValueMetricProducer::pullAndMatchEventsLocked(const int64_t timestampNs) {
vector<std::shared_ptr<LogEvent>> allData;
if (mPullerManager->Pull(mPullTagId, timestampNs, &allData)) {
- if (allData.size() == 0) {
- return;
- }
for (const auto& data : allData) {
if (mEventMatcherWizard->matchLogEvent(
*data, mWhatMatcherIndex) == MatchingState::kMatched) {
onMatchedLogEventLocked(mWhatMatcherIndex, *data);
}
}
+ mHasGlobalBase = true;
+ } else {
+ // for pulled data, every pull is needed. So we reset the base if any
+ // pull fails.
+ resetBase();
}
}
@@ -376,6 +387,7 @@
onMatchedLogEventLocked(mWhatMatcherIndex, *data);
}
}
+ mHasGlobalBase = true;
} else {
VLOG("No need to commit data on condition false.");
}
@@ -486,11 +498,18 @@
}
if (mUseDiff) {
- // no base. just update base and return.
if (!interval.hasBase) {
- interval.base = value;
- interval.hasBase = true;
- return;
+ if (mHasGlobalBase && mUseZeroDefaultBase) {
+ // The bucket has global base. This key does not.
+ // Optionally use zero as base.
+ interval.base = (value.type == LONG ? ZERO_LONG : ZERO_DOUBLE);
+ interval.hasBase = true;
+ } else {
+ // no base. just update base and return.
+ interval.base = value;
+ interval.hasBase = true;
+ return;
+ }
}
Value diff;
switch (mValueDirection) {
@@ -580,11 +599,7 @@
if (numBucketsForward > 1) {
VLOG("Skipping forward %lld buckets", (long long)numBucketsForward);
// take base again in future good bucket.
- for (auto& slice : mCurrentSlicedBucket) {
- for (auto& interval : slice.second) {
- interval.hasBase = false;
- }
- }
+ resetBase();
}
VLOG("metric %lld: new bucket start time: %lld", (long long)mMetricId,
(long long)mCurrentBucketStartTimeNs);
diff --git a/cmds/statsd/src/metrics/ValueMetricProducer.h b/cmds/statsd/src/metrics/ValueMetricProducer.h
index 9fe84dc..36ae214 100644
--- a/cmds/statsd/src/metrics/ValueMetricProducer.h
+++ b/cmds/statsd/src/metrics/ValueMetricProducer.h
@@ -148,6 +148,9 @@
void pullAndMatchEventsLocked(const int64_t timestampNs);
+ // Reset diff base and mHasGlobalBase
+ void resetBase();
+
static const size_t kBucketSize = sizeof(ValueBucket{});
const size_t mDimensionSoftLimit;
@@ -164,6 +167,18 @@
const bool mSkipZeroDiffOutput;
+ // If true, use a zero value as base to compute the diff.
+ // This is used for new keys which are present in the new data but was not
+ // present in the base data.
+ // The default base will only be used if we have a global base.
+ const bool mUseZeroDefaultBase;
+
+ // For pulled metrics, this is always set to true whenever a pull succeeds.
+ // It is set to false when a pull fails, or upon condition change to false.
+ // This is used to decide if we have the right base data to compute the
+ // diff against.
+ bool mHasGlobalBase;
+
FRIEND_TEST(ValueMetricProducerTest, TestPulledEventsNoCondition);
FRIEND_TEST(ValueMetricProducerTest, TestPulledEventsWithFiltering);
FRIEND_TEST(ValueMetricProducerTest, TestPulledEventsTakeAbsoluteValueOnReset);
@@ -185,6 +200,8 @@
FRIEND_TEST(ValueMetricProducerTest, TestFirstBucket);
FRIEND_TEST(ValueMetricProducerTest, TestCalcPreviousBucketEndTime);
FRIEND_TEST(ValueMetricProducerTest, TestSkipZeroDiffOutput);
+ FRIEND_TEST(ValueMetricProducerTest, TestUseZeroDefaultBase);
+ FRIEND_TEST(ValueMetricProducerTest, TestUseZeroDefaultBaseWithPullFailures);
};
} // namespace statsd
diff --git a/cmds/statsd/src/stats_log.proto b/cmds/statsd/src/stats_log.proto
index 32ee5af..a6f27c8 100644
--- a/cmds/statsd/src/stats_log.proto
+++ b/cmds/statsd/src/stats_log.proto
@@ -219,6 +219,8 @@
optional DimensionsValue dimensions_path_in_what = 11;
optional DimensionsValue dimensions_path_in_condition = 12;
+
+ optional bool is_active = 13;
}
message UidMapping {
diff --git a/cmds/statsd/src/statsd_config.proto b/cmds/statsd/src/statsd_config.proto
index 61854a4..f485185 100644
--- a/cmds/statsd/src/statsd_config.proto
+++ b/cmds/statsd/src/statsd_config.proto
@@ -274,6 +274,8 @@
optional bool use_diff = 12;
+ optional bool use_zero_default_base = 15 [default = false];
+
enum ValueDirection {
UNKNOWN = 0;
INCREASING = 1;
diff --git a/cmds/statsd/tests/e2e/PartialBucket_e2e_test.cpp b/cmds/statsd/tests/e2e/PartialBucket_e2e_test.cpp
index 2b0285b..370c36c 100644
--- a/cmds/statsd/tests/e2e/PartialBucket_e2e_test.cpp
+++ b/cmds/statsd/tests/e2e/PartialBucket_e2e_test.cpp
@@ -119,7 +119,8 @@
ConfigMetricsReport report = GetReports(service.mProcessor, start + 3);
// Expect no metrics since the bucket has not finished yet.
- EXPECT_EQ(0, report.metrics_size());
+ EXPECT_EQ(1, report.metrics_size());
+ EXPECT_EQ(0, report.metrics(0).count_metrics().data_size());
}
TEST(PartialBucketE2eTest, TestCountMetricNoSplitOnNewApp) {
@@ -138,7 +139,8 @@
service.mProcessor->OnLogEvent(CreateAppCrashEvent(100, start + 3).get());
ConfigMetricsReport report = GetReports(service.mProcessor, start + 4);
- EXPECT_EQ(0, report.metrics_size());
+ EXPECT_EQ(1, report.metrics_size());
+ EXPECT_EQ(0, report.metrics(0).count_metrics().data_size());
}
TEST(PartialBucketE2eTest, TestCountMetricSplitOnUpgrade) {
diff --git a/cmds/statsd/tests/e2e/WakelockDuration_e2e_test.cpp b/cmds/statsd/tests/e2e/WakelockDuration_e2e_test.cpp
index 6d1317c..16be3d7 100644
--- a/cmds/statsd/tests/e2e/WakelockDuration_e2e_test.cpp
+++ b/cmds/statsd/tests/e2e/WakelockDuration_e2e_test.cpp
@@ -262,7 +262,8 @@
// When using ProtoOutputStream, if nothing written to a sub msg, it won't be treated as
// one. It was previsouly 1 because we had a fake onDumpReport which calls add_metric() by
// itself.
- EXPECT_EQ(0, reports.reports(0).metrics_size());
+ EXPECT_EQ(1, reports.reports(0).metrics_size());
+ EXPECT_EQ(0, reports.reports(0).metrics(0).duration_metrics().data_size());
}
TEST(WakelockDurationE2eTest, TestAggregatedPredicateDimensionsForMaxDuration2) {
diff --git a/cmds/statsd/tests/metrics/ValueMetricProducer_test.cpp b/cmds/statsd/tests/metrics/ValueMetricProducer_test.cpp
index 44aa00b..1bd34f5 100644
--- a/cmds/statsd/tests/metrics/ValueMetricProducer_test.cpp
+++ b/cmds/statsd/tests/metrics/ValueMetricProducer_test.cpp
@@ -1468,6 +1468,219 @@
EXPECT_EQ(5, valueProducer.mPastBuckets.begin()->second.back().values[0].long_value);
}
+/*
+ * Tests pulled atoms with no conditions
+ */
+TEST(ValueMetricProducerTest, TestUseZeroDefaultBase) {
+ ValueMetric metric;
+ metric.set_id(metricId);
+ metric.set_bucket(ONE_MINUTE);
+ metric.mutable_value_field()->set_field(tagId);
+ metric.mutable_value_field()->add_child()->set_field(2);
+ metric.mutable_dimensions_in_what()->set_field(tagId);
+ metric.mutable_dimensions_in_what()->add_child()->set_field(1);
+ metric.set_use_zero_default_base(true);
+
+ UidMap uidMap;
+ SimpleAtomMatcher atomMatcher;
+ atomMatcher.set_atom_id(tagId);
+ sp<EventMatcherWizard> eventMatcherWizard =
+ new EventMatcherWizard({new SimpleLogMatchingTracker(
+ atomMatcherId, logEventMatcherIndex, atomMatcher, uidMap)});
+ sp<MockConditionWizard> wizard = new NaggyMock<MockConditionWizard>();
+ sp<MockStatsPullerManager> pullerManager = new StrictMock<MockStatsPullerManager>();
+ EXPECT_CALL(*pullerManager, RegisterReceiver(tagId, _, _, _)).WillOnce(Return());
+ EXPECT_CALL(*pullerManager, UnRegisterReceiver(tagId, _)).WillOnce(Return());
+ EXPECT_CALL(*pullerManager, Pull(tagId, _, _))
+ .WillOnce(Invoke([](int tagId, int64_t timeNs,
+ vector<std::shared_ptr<LogEvent>>* data) {
+ data->clear();
+ shared_ptr<LogEvent> event = make_shared<LogEvent>(tagId, bucketStartTimeNs);
+ event->write(1);
+ event->write(3);
+ event->init();
+ data->push_back(event);
+ return true;
+ }));
+
+ ValueMetricProducer valueProducer(kConfigKey, metric, -1 /*-1 meaning no condition*/, wizard,
+ logEventMatcherIndex, eventMatcherWizard, tagId,
+ bucketStartTimeNs, bucketStartTimeNs, pullerManager);
+
+ EXPECT_EQ(1UL, valueProducer.mCurrentSlicedBucket.size());
+ auto iter = valueProducer.mCurrentSlicedBucket.begin();
+ auto& interval1 = iter->second[0];
+ EXPECT_EQ(1, iter->first.getDimensionKeyInWhat().getValues()[0].mValue.int_value);
+ EXPECT_EQ(true, interval1.hasBase);
+ EXPECT_EQ(3, interval1.base.long_value);
+ EXPECT_EQ(false, interval1.hasValue);
+ EXPECT_EQ(true, valueProducer.mHasGlobalBase);
+ EXPECT_EQ(0UL, valueProducer.mPastBuckets.size());
+ vector<shared_ptr<LogEvent>> allData;
+
+ allData.clear();
+ shared_ptr<LogEvent> event1 = make_shared<LogEvent>(tagId, bucket2StartTimeNs + 1);
+ event1->write(2);
+ event1->write(4);
+ event1->init();
+ shared_ptr<LogEvent> event2 = make_shared<LogEvent>(tagId, bucket2StartTimeNs + 1);
+ event2->write(1);
+ event2->write(11);
+ event2->init();
+ allData.push_back(event1);
+ allData.push_back(event2);
+
+ valueProducer.onDataPulled(allData);
+ EXPECT_EQ(2UL, valueProducer.mCurrentSlicedBucket.size());
+ EXPECT_EQ(true, interval1.hasBase);
+ EXPECT_EQ(11, interval1.base.long_value);
+ EXPECT_EQ(true, interval1.hasValue);
+ EXPECT_EQ(8, interval1.value.long_value);
+
+ auto it = valueProducer.mCurrentSlicedBucket.begin();
+ for (; it != valueProducer.mCurrentSlicedBucket.end(); it++) {
+ if (it != iter) {
+ break;
+ }
+ }
+ EXPECT_TRUE(it != iter);
+ auto& interval2 = it->second[0];
+ EXPECT_EQ(2, it->first.getDimensionKeyInWhat().getValues()[0].mValue.int_value);
+ EXPECT_EQ(true, interval2.hasBase);
+ EXPECT_EQ(4, interval2.base.long_value);
+ EXPECT_EQ(true, interval2.hasValue);
+ EXPECT_EQ(4, interval2.value.long_value);
+ EXPECT_EQ(0UL, valueProducer.mPastBuckets.size());
+}
+
+/*
+ * Tests pulled atoms with no conditions
+ */
+TEST(ValueMetricProducerTest, TestUseZeroDefaultBaseWithPullFailures) {
+ ValueMetric metric;
+ metric.set_id(metricId);
+ metric.set_bucket(ONE_MINUTE);
+ metric.mutable_value_field()->set_field(tagId);
+ metric.mutable_value_field()->add_child()->set_field(2);
+ metric.mutable_dimensions_in_what()->set_field(tagId);
+ metric.mutable_dimensions_in_what()->add_child()->set_field(1);
+ metric.set_use_zero_default_base(true);
+
+ UidMap uidMap;
+ SimpleAtomMatcher atomMatcher;
+ atomMatcher.set_atom_id(tagId);
+ sp<EventMatcherWizard> eventMatcherWizard =
+ new EventMatcherWizard({new SimpleLogMatchingTracker(
+ atomMatcherId, logEventMatcherIndex, atomMatcher, uidMap)});
+ sp<MockConditionWizard> wizard = new NaggyMock<MockConditionWizard>();
+ sp<MockStatsPullerManager> pullerManager = new StrictMock<MockStatsPullerManager>();
+ EXPECT_CALL(*pullerManager, RegisterReceiver(tagId, _, _, _)).WillOnce(Return());
+ EXPECT_CALL(*pullerManager, UnRegisterReceiver(tagId, _)).WillOnce(Return());
+ EXPECT_CALL(*pullerManager, Pull(tagId, _, _))
+ .WillOnce(Invoke([](int tagId, int64_t timeNs,
+ vector<std::shared_ptr<LogEvent>>* data) {
+ data->clear();
+ shared_ptr<LogEvent> event = make_shared<LogEvent>(tagId, bucketStartTimeNs);
+ event->write(1);
+ event->write(3);
+ event->init();
+ data->push_back(event);
+ return true;
+ }));
+
+ ValueMetricProducer valueProducer(kConfigKey, metric, -1 /*-1 meaning no condition*/, wizard,
+ logEventMatcherIndex, eventMatcherWizard, tagId,
+ bucketStartTimeNs, bucketStartTimeNs, pullerManager);
+
+ EXPECT_EQ(1UL, valueProducer.mCurrentSlicedBucket.size());
+ auto iter = valueProducer.mCurrentSlicedBucket.begin();
+ auto& interval1 = iter->second[0];
+ EXPECT_EQ(1, iter->first.getDimensionKeyInWhat().getValues()[0].mValue.int_value);
+ EXPECT_EQ(true, interval1.hasBase);
+ EXPECT_EQ(3, interval1.base.long_value);
+ EXPECT_EQ(false, interval1.hasValue);
+ EXPECT_EQ(true, valueProducer.mHasGlobalBase);
+ EXPECT_EQ(0UL, valueProducer.mPastBuckets.size());
+ vector<shared_ptr<LogEvent>> allData;
+
+ allData.clear();
+ shared_ptr<LogEvent> event1 = make_shared<LogEvent>(tagId, bucket2StartTimeNs + 1);
+ event1->write(2);
+ event1->write(4);
+ event1->init();
+ shared_ptr<LogEvent> event2 = make_shared<LogEvent>(tagId, bucket2StartTimeNs + 1);
+ event2->write(1);
+ event2->write(11);
+ event2->init();
+ allData.push_back(event1);
+ allData.push_back(event2);
+
+ valueProducer.onDataPulled(allData);
+ EXPECT_EQ(2UL, valueProducer.mCurrentSlicedBucket.size());
+ EXPECT_EQ(true, interval1.hasBase);
+ EXPECT_EQ(11, interval1.base.long_value);
+ EXPECT_EQ(true, interval1.hasValue);
+ EXPECT_EQ(8, interval1.value.long_value);
+
+ auto it = valueProducer.mCurrentSlicedBucket.begin();
+ for (; it != valueProducer.mCurrentSlicedBucket.end(); it++) {
+ if (it != iter) {
+ break;
+ }
+ }
+ EXPECT_TRUE(it != iter);
+ auto& interval2 = it->second[0];
+ EXPECT_EQ(2, it->first.getDimensionKeyInWhat().getValues()[0].mValue.int_value);
+ EXPECT_EQ(true, interval2.hasBase);
+ EXPECT_EQ(4, interval2.base.long_value);
+ EXPECT_EQ(true, interval2.hasValue);
+ EXPECT_EQ(4, interval2.value.long_value);
+ EXPECT_EQ(0UL, valueProducer.mPastBuckets.size());
+
+ // next pull somehow did not happen, skip to end of bucket 3
+ allData.clear();
+ event1 = make_shared<LogEvent>(tagId, bucket4StartTimeNs + 1);
+ event1->write(2);
+ event1->write(5);
+ event1->init();
+ allData.push_back(event1);
+ valueProducer.onDataPulled(allData);
+
+ EXPECT_EQ(2UL, valueProducer.mCurrentSlicedBucket.size());
+ EXPECT_EQ(true, interval2.hasBase);
+ EXPECT_EQ(5, interval2.base.long_value);
+ EXPECT_EQ(false, interval2.hasValue);
+ EXPECT_EQ(false, interval1.hasBase);
+ EXPECT_EQ(false, interval1.hasValue);
+ EXPECT_EQ(true, valueProducer.mHasGlobalBase);
+ EXPECT_EQ(2UL, valueProducer.mPastBuckets.size());
+
+ allData.clear();
+ event1 = make_shared<LogEvent>(tagId, bucket5StartTimeNs + 1);
+ event1->write(2);
+ event1->write(13);
+ event1->init();
+ allData.push_back(event1);
+ event2 = make_shared<LogEvent>(tagId, bucket5StartTimeNs + 1);
+ event2->write(1);
+ event2->write(5);
+ event2->init();
+ allData.push_back(event2);
+ valueProducer.onDataPulled(allData);
+
+ EXPECT_EQ(2UL, valueProducer.mCurrentSlicedBucket.size());
+ EXPECT_EQ(true, interval2.hasBase);
+ EXPECT_EQ(13, interval2.base.long_value);
+ EXPECT_EQ(true, interval2.hasValue);
+ EXPECT_EQ(8, interval2.value.long_value);
+ EXPECT_EQ(true, interval1.hasBase);
+ EXPECT_EQ(5, interval1.base.long_value);
+ EXPECT_EQ(true, interval1.hasValue);
+ EXPECT_EQ(5, interval1.value.long_value);
+ EXPECT_EQ(true, valueProducer.mHasGlobalBase);
+ EXPECT_EQ(2UL, valueProducer.mPastBuckets.size());
+}
+
} // namespace statsd
} // namespace os
} // namespace android
diff --git a/config/hiddenapi-greylist.txt b/config/hiddenapi-greylist.txt
index 01c7028..56dc4c1 100644
--- a/config/hiddenapi-greylist.txt
+++ b/config/hiddenapi-greylist.txt
@@ -1849,13 +1849,16 @@
Lcom/android/internal/location/GpsNetInitiatedHandler;->mIsHexInput:Z
Lcom/android/internal/location/ILocationProvider$Stub;-><init>()V
Lcom/android/internal/location/ILocationProvider$Stub;->asInterface(Landroid/os/IBinder;)Lcom/android/internal/location/ILocationProvider;
-Lcom/android/internal/location/ILocationProvider;->disable()V
-Lcom/android/internal/location/ILocationProvider;->enable()V
-Lcom/android/internal/location/ILocationProvider;->getProperties()Lcom/android/internal/location/ProviderProperties;
Lcom/android/internal/location/ILocationProvider;->getStatus(Landroid/os/Bundle;)I
Lcom/android/internal/location/ILocationProvider;->getStatusUpdateTime()J
-Lcom/android/internal/location/ILocationProvider;->sendExtraCommand(Ljava/lang/String;Landroid/os/Bundle;)Z
+Lcom/android/internal/location/ILocationProvider;->sendExtraCommand(Ljava/lang/String;Landroid/os/Bundle;)V
+Lcom/android/internal/location/ILocationProvider;->setLocationProviderManager(Lcom/android/internal/location/ILocationProviderManager;)V
Lcom/android/internal/location/ILocationProvider;->setRequest(Lcom/android/internal/location/ProviderRequest;Landroid/os/WorkSource;)V
+Lcom/android/internal/location/ILocationProviderManager$Stub;-><init>()V
+Lcom/android/internal/location/ILocationProviderManager$Stub;->asInterface(Landroid/os/IBinder;)Lcom/android/internal/location/ILocationProviderManager;
+Lcom/android/internal/location/ILocationProviderManager;->onReportLocation(Landroid/location/Location;)V
+Lcom/android/internal/location/ILocationProviderManager;->onSetEnabled(Z)V
+Lcom/android/internal/location/ILocationProviderManager;->onSetProperties(Lcom/android/internal/location/ProviderProperties;)V
Lcom/android/internal/logging/MetricsLogger;-><init>()V
Lcom/android/internal/net/LegacyVpnInfo;-><init>()V
Lcom/android/internal/net/VpnConfig;-><init>()V
diff --git a/core/java/android/annotation/UnsupportedAppUsage.java b/core/java/android/annotation/UnsupportedAppUsage.java
index 28145a0..65e3f25 100644
--- a/core/java/android/annotation/UnsupportedAppUsage.java
+++ b/core/java/android/annotation/UnsupportedAppUsage.java
@@ -18,8 +18,10 @@
import static java.lang.annotation.ElementType.CONSTRUCTOR;
import static java.lang.annotation.ElementType.FIELD;
import static java.lang.annotation.ElementType.METHOD;
+import static java.lang.annotation.ElementType.TYPE;
import static java.lang.annotation.RetentionPolicy.CLASS;
+import java.lang.annotation.Repeatable;
import java.lang.annotation.Retention;
import java.lang.annotation.Target;
@@ -40,7 +42,8 @@
* {@hide}
*/
@Retention(CLASS)
-@Target({CONSTRUCTOR, METHOD, FIELD})
+@Target({CONSTRUCTOR, METHOD, FIELD, TYPE})
+@Repeatable(UnsupportedAppUsage.Container.class)
public @interface UnsupportedAppUsage {
/**
@@ -90,4 +93,27 @@
* @return A dex API signature.
*/
String expectedSignature() default "";
+
+ /**
+ * The signature of an implicit (not present in the source) member that forms part of the
+ * hiddenapi.
+ *
+ * <p>Allows access to non-SDK API elements that are not represented in the input source to be
+ * managed.
+ *
+ * <p>This must only be used when applying the annotation to a type, using it in any other
+ * situation is an error.
+ *
+ * @return A dex API signature.
+ */
+ String implicitMember() default "";
+
+ /**
+ * Container for {@link UnsupportedAppUsage} that allows it to be applied repeatedly to types.
+ */
+ @Retention(CLASS)
+ @Target(TYPE)
+ @interface Container {
+ UnsupportedAppUsage[] value();
+ }
}
diff --git a/core/java/android/app/Activity.java b/core/java/android/app/Activity.java
index cfda803..61b9d55 100644
--- a/core/java/android/app/Activity.java
+++ b/core/java/android/app/Activity.java
@@ -1723,15 +1723,7 @@
if (mAutoFillResetNeeded) {
if (!mAutoFillIgnoreFirstResumePause) {
View focus = getCurrentFocus();
- // On Activity rotation situation (mRestoredFromBundle is true),
- // we should not call on AutofillManager in onResume()
- // since the next Layout pass will do that.
- // However, there are both cases where Activity#getCurrentFocus()
- // will return null (window not preserved) and not null (window IS
- // preserved), so we need to explicitly check for mRestoredFromBundle
- // here.
- if (!mRestoredFromBundle && focus != null
- && focus.canNotifyAutofillEnterExitEvent()) {
+ if (focus != null && focus.canNotifyAutofillEnterExitEvent()) {
// TODO: in Activity killed/recreated case, i.e. SessionLifecycleTest#
// testDatasetVisibleWhileAutofilledAppIsLifecycled: the View's initial
// window visibility after recreation is INVISIBLE in onResume() and next frame
diff --git a/core/java/android/app/ActivityManager.java b/core/java/android/app/ActivityManager.java
index 1cf042f..84c7785 100644
--- a/core/java/android/app/ActivityManager.java
+++ b/core/java/android/app/ActivityManager.java
@@ -3676,6 +3676,18 @@
}
/**
+ * Returns whether switching to provided user was successful.
+ *
+ * @param user the user to switch to.
+ * @hide
+ */
+ @SystemApi
+ @RequiresPermission(android.Manifest.permission.MANAGE_USERS)
+ public boolean switchUser(UserHandle user) {
+ return switchUser(user.getIdentifier());
+ }
+
+ /**
* Logs out current current foreground user by switching to the system user and stopping the
* user being switched from.
* @hide
diff --git a/core/java/android/app/ActivityThread.java b/core/java/android/app/ActivityThread.java
index 41166dd..fe9b1ff 100644
--- a/core/java/android/app/ActivityThread.java
+++ b/core/java/android/app/ActivityThread.java
@@ -162,7 +162,6 @@
import com.android.org.conscrypt.TrustedCertificateStore;
import com.android.server.am.MemInfoDumpProto;
-import dalvik.system.BaseDexClassLoader;
import dalvik.system.CloseGuard;
import dalvik.system.VMDebug;
import dalvik.system.VMRuntime;
@@ -2282,6 +2281,15 @@
}
}
+ /**
+ * Create the context instance base on system resources & display information which used for UI.
+ * @param displayId The ID of the display where the UI is shown.
+ * @see ContextImpl#createSystemUiContext(ContextImpl, int)
+ */
+ public ContextImpl createSystemUiContext(int displayId) {
+ return ContextImpl.createSystemUiContext(getSystemUiContext(), displayId);
+ }
+
public void installSystemApplicationInfo(ApplicationInfo info, ClassLoader classLoader) {
synchronized (this) {
getSystemContext().installSystemApplicationInfo(info, classLoader);
@@ -5948,16 +5956,6 @@
HardwareRenderer.setIsolatedProcess(true);
}
- // If we use profiles, setup the dex reporter to notify package manager
- // of any relevant dex loads. The idle maintenance job will use the information
- // reported to optimize the loaded dex files.
- // Note that we only need one global reporter per app.
- // Make sure we do this before calling onCreate so that we can capture the
- // complete application startup.
- if (SystemProperties.getBoolean("dalvik.vm.usejitprofiles", false)) {
- BaseDexClassLoader.setReporter(DexLoadReporter.getInstance());
- }
-
// Install the Network Security Config Provider. This must happen before the application
// code is loaded to prevent issues with instances of TLS objects being created before
// the provider is installed.
diff --git a/core/java/android/app/AppOpsManager.java b/core/java/android/app/AppOpsManager.java
index 3069be6..6905cb5 100644
--- a/core/java/android/app/AppOpsManager.java
+++ b/core/java/android/app/AppOpsManager.java
@@ -476,9 +476,11 @@
public static final int OP_READ_MEDIA_IMAGES = 85;
/** @hide Write media of image type. */
public static final int OP_WRITE_MEDIA_IMAGES = 86;
+ /** @hide Has a legacy (non-isolated) view of storage. */
+ public static final int OP_LEGACY_STORAGE = 87;
/** @hide */
@UnsupportedAppUsage
- public static final int _NUM_OP = 87;
+ public static final int _NUM_OP = 88;
/** Access to coarse location information. */
public static final String OPSTR_COARSE_LOCATION = "android:coarse_location";
@@ -745,6 +747,8 @@
public static final String OPSTR_READ_MEDIA_IMAGES = "android:read_media_images";
/** @hide Write media of image type. */
public static final String OPSTR_WRITE_MEDIA_IMAGES = "android:write_media_images";
+ /** @hide Has a legacy (non-isolated) view of storage. */
+ public static final String OPSTR_LEGACY_STORAGE = "android:legacy_storage";
// Warning: If an permission is added here it also has to be added to
// com.android.packageinstaller.permission.utils.EventLogger
@@ -903,6 +907,7 @@
OP_WRITE_MEDIA_VIDEO, // WRITE_MEDIA_VIDEO
OP_READ_MEDIA_IMAGES, // READ_MEDIA_IMAGES
OP_WRITE_MEDIA_IMAGES, // WRITE_MEDIA_IMAGES
+ OP_LEGACY_STORAGE, // LEGACY_STORAGE
};
/**
@@ -996,6 +1001,7 @@
OPSTR_WRITE_MEDIA_VIDEO,
OPSTR_READ_MEDIA_IMAGES,
OPSTR_WRITE_MEDIA_IMAGES,
+ OPSTR_LEGACY_STORAGE,
};
/**
@@ -1090,6 +1096,7 @@
"WRITE_MEDIA_VIDEO",
"READ_MEDIA_IMAGES",
"WRITE_MEDIA_IMAGES",
+ "LEGACY_STORAGE",
};
/**
@@ -1185,6 +1192,7 @@
null, // no permission for OP_WRITE_MEDIA_VIDEO
Manifest.permission.READ_MEDIA_IMAGES,
null, // no permission for OP_WRITE_MEDIA_IMAGES
+ null, // no permission for OP_LEGACY_STORAGE
};
/**
@@ -1280,6 +1288,7 @@
null, // WRITE_MEDIA_VIDEO
null, // READ_MEDIA_IMAGES
null, // WRITE_MEDIA_IMAGES
+ null, // LEGACY_STORAGE
};
/**
@@ -1374,6 +1383,7 @@
false, // WRITE_MEDIA_VIDEO
false, // READ_MEDIA_IMAGES
false, // WRITE_MEDIA_IMAGES
+ false, // LEGACY_STORAGE
};
/**
@@ -1467,6 +1477,7 @@
AppOpsManager.MODE_ERRORED, // WRITE_MEDIA_VIDEO
AppOpsManager.MODE_ALLOWED, // READ_MEDIA_IMAGES
AppOpsManager.MODE_ERRORED, // WRITE_MEDIA_IMAGES
+ AppOpsManager.MODE_DEFAULT, // LEGACY_STORAGE
};
/**
@@ -1564,6 +1575,7 @@
false, // WRITE_MEDIA_VIDEO
false, // READ_MEDIA_IMAGES
false, // WRITE_MEDIA_IMAGES
+ false, // LEGACY_STORAGE
};
/**
@@ -2490,30 +2502,6 @@
}
/**
- * Retrieve current operation state for all applications.
- *
- * @param ops The set of operations you are interested in, or null if you want all of them.
- * @hide
- */
- @RequiresPermission(android.Manifest.permission.GET_APP_OPS_STATS)
- @SystemApi
- public List<AppOpsManager.PackageOps> getPackagesForOpStrs(String[] ops) {
- if (ops == null) {
- return getPackagesForOps(null);
- }
- final int[] opCodes = new int[ops.length];
- for (int i = 0; i < ops.length; ++i) {
- final Integer opCode = sOpStrToOp.get(ops[i]);
- if (opCode == null) {
- opCodes[i] = OP_NONE;
- } else {
- opCodes[i] = opCode;
- }
- }
- return getPackagesForOps(opCodes);
- }
-
- /**
* Retrieve current operation state for one application.
*
* @param uid The uid of the application of interest.
diff --git a/core/java/android/app/ApplicationPackageManager.java b/core/java/android/app/ApplicationPackageManager.java
index 7312b2c..67d9ad6e 100644
--- a/core/java/android/app/ApplicationPackageManager.java
+++ b/core/java/android/app/ApplicationPackageManager.java
@@ -2974,6 +2974,15 @@
}
@Override
+ public String getWellbeingPackageName() {
+ try {
+ return mPM.getWellbeingPackageName();
+ } catch (RemoteException e) {
+ throw e.rethrowAsRuntimeException();
+ }
+ }
+
+ @Override
public boolean isPackageStateProtected(String packageName, int userId) {
try {
return mPM.isPackageStateProtected(packageName, userId);
diff --git a/core/java/android/app/ContextImpl.java b/core/java/android/app/ContextImpl.java
index c7a9d99..92cdb20 100644
--- a/core/java/android/app/ContextImpl.java
+++ b/core/java/android/app/ContextImpl.java
@@ -2407,16 +2407,28 @@
/**
* System Context to be used for UI. This Context has resources that can be themed.
* Make sure that the created system UI context shares the same LoadedApk as the system context.
+ * @param systemContext The system context which created by
+ * {@link #createSystemContext(ActivityThread)}.
+ * @param displayId The ID of the display where the UI is shown.
*/
- static ContextImpl createSystemUiContext(ContextImpl systemContext) {
+ static ContextImpl createSystemUiContext(ContextImpl systemContext, int displayId) {
final LoadedApk packageInfo = systemContext.mPackageInfo;
ContextImpl context = new ContextImpl(null, systemContext.mMainThread, packageInfo, null,
null, null, 0, null);
- context.setResources(createResources(null, packageInfo, null, Display.DEFAULT_DISPLAY, null,
+ context.setResources(createResources(null, packageInfo, null, displayId, null,
packageInfo.getCompatibilityInfo()));
+ context.updateDisplay(displayId);
return context;
}
+ /**
+ * The overloaded method of {@link #createSystemUiContext(ContextImpl, int)}.
+ * Uses {@Code Display.DEFAULT_DISPLAY} as the target display.
+ */
+ static ContextImpl createSystemUiContext(ContextImpl systemContext) {
+ return createSystemUiContext(systemContext, Display.DEFAULT_DISPLAY);
+ }
+
@UnsupportedAppUsage
static ContextImpl createAppContext(ActivityThread mainThread, LoadedApk packageInfo) {
if (packageInfo == null) throw new IllegalArgumentException("packageInfo");
diff --git a/core/java/android/app/LoadedApk.java b/core/java/android/app/LoadedApk.java
index 759763b..d46dbed 100644
--- a/core/java/android/app/LoadedApk.java
+++ b/core/java/android/app/LoadedApk.java
@@ -57,6 +57,7 @@
import com.android.internal.util.ArrayUtils;
+import dalvik.system.BaseDexClassLoader;
import dalvik.system.VMRuntime;
import java.io.File;
@@ -949,6 +950,15 @@
if (!SystemProperties.getBoolean("dalvik.vm.usejitprofiles", false)) {
return;
}
+
+ // If we use profiles, setup the dex reporter to notify package manager
+ // of any relevant dex loads. The idle maintenance job will use the information
+ // reported to optimize the loaded dex files.
+ // Note that we only need one global reporter per app.
+ // Make sure we do this before invoking app code for the first time so that we
+ // can capture the complete application startup.
+ BaseDexClassLoader.setReporter(DexLoadReporter.getInstance());
+
// Only set up profile support if the loaded apk has the same uid as the
// current process.
// Currently, we do not support profiling across different apps.
diff --git a/core/java/android/app/Notification.java b/core/java/android/app/Notification.java
index aa1b5af..b9d5907 100644
--- a/core/java/android/app/Notification.java
+++ b/core/java/android/app/Notification.java
@@ -4770,14 +4770,16 @@
TemplateBindResult result) {
boolean largeIconShown = bindLargeIcon(contentView, p);
boolean replyIconShown = bindReplyIcon(contentView, p);
+ boolean iconContainerVisible = largeIconShown || replyIconShown;
contentView.setViewVisibility(R.id.right_icon_container,
- largeIconShown || replyIconShown ? View.VISIBLE : View.GONE);
+ iconContainerVisible ? View.VISIBLE : View.GONE);
int marginEnd = calculateMarginEnd(largeIconShown, replyIconShown);
contentView.setViewLayoutMarginEnd(R.id.line1, marginEnd);
contentView.setViewLayoutMarginEnd(R.id.text, marginEnd);
contentView.setViewLayoutMarginEnd(R.id.progress, marginEnd);
if (result != null) {
result.setIconMarginEnd(marginEnd);
+ result.setRightIconContainerVisible(iconContainerVisible);
}
}
@@ -6777,7 +6779,8 @@
mBuilder.setTextViewColorSecondary(contentView, R.id.big_text, p);
contentView.setViewVisibility(R.id.big_text,
TextUtils.isEmpty(bigTextText) ? View.GONE : View.VISIBLE);
- contentView.setBoolean(R.id.big_text, "setHasImage", mBuilder.mN.hasLargeIcon());
+ contentView.setBoolean(R.id.big_text, "setHasImage",
+ result.isRightIconContainerVisible());
return contentView;
}
@@ -9914,6 +9917,7 @@
*/
private static class TemplateBindResult {
int mIconMarginEnd;
+ boolean mRightIconContainerVisible;
/**
* Get the margin end that needs to be added to any fields that may overlap
@@ -9923,9 +9927,21 @@
return mIconMarginEnd;
}
+ /**
+ * Is the icon container visible on the right size because of the reply button or the
+ * right icon.
+ */
+ public boolean isRightIconContainerVisible() {
+ return mRightIconContainerVisible;
+ }
+
public void setIconMarginEnd(int iconMarginEnd) {
this.mIconMarginEnd = iconMarginEnd;
}
+
+ public void setRightIconContainerVisible(boolean iconContainerVisible) {
+ mRightIconContainerVisible = iconContainerVisible;
+ }
}
private static class StandardTemplateParams {
diff --git a/core/java/android/app/Service.java b/core/java/android/app/Service.java
index 16f6bda..5fa8526 100644
--- a/core/java/android/app/Service.java
+++ b/core/java/android/app/Service.java
@@ -685,6 +685,13 @@
* the permission {@link android.Manifest.permission#FOREGROUND_SERVICE} in order to use
* this API.</p>
*
+ * <p>To use this API, apps targeting API {@link android.os.Build.VERSION_CODES#Q} or later must
+ * specify the foreground service type using attribute
+ * {@link android.R.attr#foregroundServiceType} in service element of manifest file, otherwise
+ * a SecurityException is thrown when this API is called. Apps targeting API older than
+ * {@link android.os.Build.VERSION_CODES#Q} do not need to specify the foreground service type
+ * </p>
+ *
* @param id The identifier for this notification as per
* {@link NotificationManager#notify(int, Notification)
* NotificationManager.notify(int, Notification)}; must not be 0.
@@ -700,7 +707,7 @@
} catch (RemoteException ex) {
}
}
-
+
/**
* Synonym for {@link #stopForeground(int)}.
* @param removeNotification If true, the {@link #STOP_FOREGROUND_REMOVE} flag
diff --git a/core/java/android/app/UiAutomationConnection.java b/core/java/android/app/UiAutomationConnection.java
index dc2f983..31521a3 100644
--- a/core/java/android/app/UiAutomationConnection.java
+++ b/core/java/android/app/UiAutomationConnection.java
@@ -331,7 +331,7 @@
writeTo.flush();
}
} catch (IOException ioe) {
- throw new RuntimeException("Error while reading/writing ", ioe);
+ Log.w(TAG, "Error while reading/writing to streams");
} finally {
IoUtils.closeQuietly(readFrom);
IoUtils.closeQuietly(writeTo);
diff --git a/core/java/android/app/admin/DevicePolicyEventLogger.java b/core/java/android/app/admin/DevicePolicyEventLogger.java
index f39a5f4..c89d868 100644
--- a/core/java/android/app/admin/DevicePolicyEventLogger.java
+++ b/core/java/android/app/admin/DevicePolicyEventLogger.java
@@ -16,6 +16,8 @@
package android.app.admin;
+import android.annotation.Nullable;
+import android.content.ComponentName;
import android.stats.devicepolicy.nano.StringList;
import android.util.StatsLog;
@@ -34,7 +36,7 @@
*
* DevicePolicyEventLogger
* .createEvent(DevicePolicyEnums.USER_RESTRICTION_CHANGED)
- * .setAdminPackageName(who)
+ * .setAdmin(who)
* .setString(key)
* .setBoolean(enabledFromThisOwner)
* .write();
@@ -170,12 +172,20 @@
/**
* Sets the package name of the admin application.
*/
- public DevicePolicyEventLogger setAdminPackageName(String packageName) {
+ public DevicePolicyEventLogger setAdmin(@Nullable String packageName) {
mAdminPackageName = packageName;
return this;
}
/**
+ * Retrieves the package name of the admin application from the {@link ComponentName}.
+ */
+ public DevicePolicyEventLogger setAdmin(@Nullable ComponentName componentName) {
+ mAdminPackageName = (componentName != null ? componentName.getPackageName() : null);
+ return this;
+ }
+
+ /**
* Returns the package name of the admin application.
*/
@VisibleForTesting
diff --git a/core/java/android/app/admin/DevicePolicyManager.java b/core/java/android/app/admin/DevicePolicyManager.java
index 3a97284..8e54961 100644
--- a/core/java/android/app/admin/DevicePolicyManager.java
+++ b/core/java/android/app/admin/DevicePolicyManager.java
@@ -49,6 +49,8 @@
import android.content.pm.ParceledListSlice;
import android.content.pm.UserInfo;
import android.graphics.Bitmap;
+import android.net.NetworkUtils;
+import android.net.PrivateDnsConnectivityChecker;
import android.net.ProxyInfo;
import android.net.Uri;
import android.os.Binder;
@@ -79,6 +81,7 @@
import android.service.restrictions.RestrictionsReceiver;
import android.telephony.TelephonyManager;
import android.telephony.data.ApnSetting;
+import android.text.TextUtils;
import android.util.ArraySet;
import android.util.Log;
@@ -1121,6 +1124,64 @@
"android.app.extra.PROVISIONING_USE_MOBILE_DATA";
/**
+ * A String extra holding the provisioning trigger. It could be one of
+ * {@link #PROVISIONING_TRIGGER_CLOUD_ENROLLMENT}, {@link #PROVISIONING_TRIGGER_QR_CODE},
+ * {@link #PROVISIONING_TRIGGER_PERSISTENT_DEVICE_OWNER} or {@link
+ * #PROVISIONING_TRIGGER_UNSPECIFIED}.
+ *
+ * <p>Use in an intent with action {@link
+ * #ACTION_PROVISION_MANAGED_DEVICE_FROM_TRUSTED_SOURCE}.
+ * @hide
+ */
+ @SystemApi
+ public static final String EXTRA_PROVISIONING_TRIGGER =
+ "android.app.extra.PROVISIONING_TRIGGER";
+
+ /**
+ * A value for {@link #EXTRA_PROVISIONING_TRIGGER} indicating that the provisioning
+ * trigger has not been specified.
+ * @see #PROVISIONING_TRIGGER_CLOUD_ENROLLMENT
+ * @see #PROVISIONING_TRIGGER_QR_CODE
+ * @see #PROVISIONING_TRIGGER_PERSISTENT_DEVICE_OWNER
+ * @hide
+ */
+ @SystemApi
+ public static final int PROVISIONING_TRIGGER_UNSPECIFIED = 0;
+
+ /**
+ * A value for {@link #EXTRA_PROVISIONING_TRIGGER} indicating that the provisioning
+ * trigger is cloud enrollment.
+ * @see #PROVISIONING_TRIGGER_QR_CODE
+ * @see #PROVISIONING_TRIGGER_PERSISTENT_DEVICE_OWNER
+ * @see #PROVISIONING_TRIGGER_UNSPECIFIED
+ * @hide
+ */
+ @SystemApi
+ public static final int PROVISIONING_TRIGGER_CLOUD_ENROLLMENT = 1;
+
+ /**
+ * A value for {@link #EXTRA_PROVISIONING_TRIGGER} indicating that the provisioning
+ * trigger is the QR code scanner.
+ * @see #PROVISIONING_TRIGGER_CLOUD_ENROLLMENT
+ * @see #PROVISIONING_TRIGGER_PERSISTENT_DEVICE_OWNER
+ * @see #PROVISIONING_TRIGGER_UNSPECIFIED
+ * @hide
+ */
+ @SystemApi
+ public static final int PROVISIONING_TRIGGER_QR_CODE = 2;
+
+ /**
+ * A value for {@link #EXTRA_PROVISIONING_TRIGGER} indicating that the provisioning
+ * trigger is persistent device owner enrollment.
+ * @see #PROVISIONING_TRIGGER_CLOUD_ENROLLMENT
+ * @see #PROVISIONING_TRIGGER_QR_CODE
+ * @see #PROVISIONING_TRIGGER_UNSPECIFIED
+ * @hide
+ */
+ @SystemApi
+ public static final int PROVISIONING_TRIGGER_PERSISTENT_DEVICE_OWNER = 3;
+
+ /**
* This MIME type is used for starting the device owner provisioning.
*
* <p>During device owner provisioning a device admin app is set as the owner of the device.
@@ -1974,6 +2035,35 @@
public @interface InstallUpdateCallbackErrorConstants {}
/**
+ * The selected mode has been set successfully. If the mode is
+ * {@code PRIVATE_DNS_MODE_PROVIDER_HOSTNAME} then it implies the supplied host is valid
+ * and reachable.
+ */
+ public static final int PRIVATE_DNS_SET_SUCCESS = 0;
+
+ /**
+ * If the {@code privateDnsHost} provided was of a valid hostname but that host was found
+ * to not support DNS-over-TLS.
+ */
+ public static final int PRIVATE_DNS_SET_ERROR_HOST_NOT_SERVING = 1;
+
+ /**
+ * General failure to set the Private DNS mode, not due to one of the reasons listed above.
+ */
+ public static final int PRIVATE_DNS_SET_ERROR_FAILURE_SETTING = 2;
+
+ /**
+ * @hide
+ */
+ @IntDef(prefix = {"PRIVATE_DNS_SET_"}, value = {
+ PRIVATE_DNS_SET_SUCCESS,
+ PRIVATE_DNS_SET_ERROR_HOST_NOT_SERVING,
+ PRIVATE_DNS_SET_ERROR_FAILURE_SETTING
+ })
+ @Retention(RetentionPolicy.SOURCE)
+ public @interface SetPrivateDnsModeResultConstants {}
+
+ /**
* Return true if the given administrator component is currently active (enabled) in the system.
*
* @param admin The administrator component to check for.
@@ -9839,6 +9929,16 @@
* Sets the global Private DNS mode and host to be used.
* May only be called by the device owner.
*
+ * <p>Note that in case a Private DNS resolver is specified, the method is blocking as it
+ * will perform a connectivity check to the resolver, to ensure it is valid. Because of that,
+ * the method should not be called on any thread that relates to user interaction, such as the
+ * UI thread.
+ *
+ * <p>In case a VPN is used in conjunction with Private DNS resolver, the Private DNS resolver
+ * must be reachable both from within and outside the VPN. Otherwise, the device may lose
+ * the ability to resolve hostnames as system traffic to the resolver may not go through the
+ * VPN.
+ *
* @param admin which {@link DeviceAdminReceiver} this request is associated with.
* @param mode Which mode to set - either {@code PRIVATE_DNS_MODE_OPPORTUNISTIC} or
* {@code PRIVATE_DNS_MODE_PROVIDER_HOSTNAME}.
@@ -9848,6 +9948,9 @@
* @param privateDnsHost The hostname of a server that implements DNS over TLS (RFC7858), if
* {@code PRIVATE_DNS_MODE_PROVIDER_HOSTNAME} was specified as the mode,
* null otherwise.
+ *
+ * @return One of the values in {@link SetPrivateDnsModeResultConstants}.
+ *
* @throws IllegalArgumentException in the following cases: if a {@code privateDnsHost} was
* provided but the mode was not {@code PRIVATE_DNS_MODE_PROVIDER_HOSTNAME}, if the mode
* specified was {@code PRIVATE_DNS_MODE_PROVIDER_HOSTNAME} but {@code privateDnsHost} does
@@ -9855,15 +9958,23 @@
*
* @throws SecurityException if the caller is not the device owner.
*/
- public void setGlobalPrivateDns(@NonNull ComponentName admin,
+ public int setGlobalPrivateDns(@NonNull ComponentName admin,
@PrivateDnsMode int mode, @Nullable String privateDnsHost) {
throwIfParentInstance("setGlobalPrivateDns");
+
if (mService == null) {
- return;
+ return PRIVATE_DNS_SET_ERROR_FAILURE_SETTING;
+ }
+
+ if (mode == PRIVATE_DNS_MODE_PROVIDER_HOSTNAME && !TextUtils.isEmpty(privateDnsHost)
+ && NetworkUtils.isWeaklyValidatedHostname(privateDnsHost)) {
+ if (!PrivateDnsConnectivityChecker.canConnectToPrivateDnsServer(privateDnsHost)) {
+ return PRIVATE_DNS_SET_ERROR_HOST_NOT_SERVING;
+ }
}
try {
- mService.setGlobalPrivateDns(admin, mode, privateDnsHost);
+ return mService.setGlobalPrivateDns(admin, mode, privateDnsHost);
} catch (RemoteException re) {
throw re.rethrowFromSystemServer();
}
diff --git a/core/java/android/app/admin/IDevicePolicyManager.aidl b/core/java/android/app/admin/IDevicePolicyManager.aidl
index fcf74ee..1148685 100644
--- a/core/java/android/app/admin/IDevicePolicyManager.aidl
+++ b/core/java/android/app/admin/IDevicePolicyManager.aidl
@@ -415,7 +415,7 @@
boolean isMeteredDataDisabledPackageForUser(in ComponentName admin, String packageName, int userId);
- void setGlobalPrivateDns(in ComponentName admin, int mode, in String privateDnsHost);
+ int setGlobalPrivateDns(in ComponentName admin, int mode, in String privateDnsHost);
int getGlobalPrivateDnsMode(in ComponentName admin);
String getGlobalPrivateDnsHost(in ComponentName admin);
diff --git a/core/java/android/app/backup/RestoreSession.java b/core/java/android/app/backup/RestoreSession.java
index 2e0f940..79925ec 100644
--- a/core/java/android/app/backup/RestoreSession.java
+++ b/core/java/android/app/backup/RestoreSession.java
@@ -143,8 +143,6 @@
* @param packages The set of packages for which to attempt a restore. Regardless of
* the contents of the actual back-end dataset named by {@code token}, only
* applications mentioned in this list will have their data restored.
- *
- * @hide
*/
public int restoreSome(long token, RestoreObserver observer, BackupManagerMonitor monitor,
String[] packages) {
@@ -181,8 +179,6 @@
* @param packages The set of packages for which to attempt a restore. Regardless of
* the contents of the actual back-end dataset named by {@code token}, only
* applications mentioned in this list will have their data restored.
- *
- * @hide
*/
public int restoreSome(long token, RestoreObserver observer, String[] packages) {
return restoreSome(token, observer, null, packages);
diff --git a/core/java/android/app/job/JobInfo.java b/core/java/android/app/job/JobInfo.java
index 556ffa24..e84517d 100644
--- a/core/java/android/app/job/JobInfo.java
+++ b/core/java/android/app/job/JobInfo.java
@@ -200,12 +200,23 @@
public static final int PRIORITY_SYNC_INITIALIZATION = 20;
/**
- * Value of {@link #getPriority} for a foreground app (overrides the supplied
+ * Value of {@link #getPriority} for a BFGS app (overrides the supplied
+ * JobInfo priority if it is smaller).
+ * @hide
+ */
+ public static final int PRIORITY_BOUND_FOREGROUND_SERVICE = 30;
+
+ /** @hide For backward compatibility. */
+ @UnsupportedAppUsage
+ public static final int PRIORITY_FOREGROUND_APP = PRIORITY_BOUND_FOREGROUND_SERVICE;
+
+ /**
+ * Value of {@link #getPriority} for a FG service app (overrides the supplied
* JobInfo priority if it is smaller).
* @hide
*/
@UnsupportedAppUsage
- public static final int PRIORITY_FOREGROUND_APP = 30;
+ public static final int PRIORITY_FOREGROUND_SERVICE = 35;
/**
* Value of {@link #getPriority} for the current top app (overrides the supplied
@@ -1593,4 +1604,29 @@
return new JobInfo(this);
}
}
+
+ /**
+ * Convert a priority integer into a human readable string for debugging.
+ * @hide
+ */
+ public static String getPriorityString(int priority) {
+ switch (priority) {
+ case PRIORITY_DEFAULT:
+ return PRIORITY_DEFAULT + " [DEFAULT]";
+ case PRIORITY_SYNC_EXPEDITED:
+ return PRIORITY_SYNC_EXPEDITED + " [SYNC_EXPEDITED]";
+ case PRIORITY_SYNC_INITIALIZATION:
+ return PRIORITY_SYNC_INITIALIZATION + " [SYNC_INITIALIZATION]";
+ case PRIORITY_BOUND_FOREGROUND_SERVICE:
+ return PRIORITY_BOUND_FOREGROUND_SERVICE + " [BFGS_APP]";
+ case PRIORITY_FOREGROUND_SERVICE:
+ return PRIORITY_FOREGROUND_SERVICE + " [FGS_APP]";
+ case PRIORITY_TOP_APP:
+ return PRIORITY_TOP_APP + " [TOP_APP]";
+
+ // PRIORITY_ADJ_* are adjustments and not used as real priorities.
+ // No need to convert to strings.
+ }
+ return priority + " [UNKNOWN]";
+ }
}
diff --git a/core/java/android/app/job/JobParameters.java b/core/java/android/app/job/JobParameters.java
index 578a9ae..3cc56ae 100644
--- a/core/java/android/app/job/JobParameters.java
+++ b/core/java/android/app/job/JobParameters.java
@@ -47,6 +47,8 @@
public static final int REASON_TIMEOUT = JobProtoEnums.STOP_REASON_TIMEOUT; // 3.
/** @hide */
public static final int REASON_DEVICE_IDLE = JobProtoEnums.STOP_REASON_DEVICE_IDLE; // 4.
+ /** @hide */
+ public static final int REASON_DEVICE_THERMAL = JobProtoEnums.STOP_REASON_DEVICE_THERMAL; // 5.
/** @hide */
public static String getReasonName(int reason) {
diff --git a/core/java/android/app/role/RoleManager.java b/core/java/android/app/role/RoleManager.java
index 7cb245a..f3b2153 100644
--- a/core/java/android/app/role/RoleManager.java
+++ b/core/java/android/app/role/RoleManager.java
@@ -22,6 +22,7 @@
import android.annotation.RequiresPermission;
import android.annotation.SystemApi;
import android.annotation.SystemService;
+import android.annotation.TestApi;
import android.content.Context;
import android.content.Intent;
import android.os.Binder;
@@ -212,6 +213,7 @@
@NonNull
@RequiresPermission(Manifest.permission.MANAGE_ROLE_HOLDERS)
@SystemApi
+ @TestApi
public List<String> getRoleHolders(@NonNull String roleName) {
return getRoleHoldersAsUser(roleName, Process.myUserHandle());
}
@@ -239,6 +241,7 @@
@NonNull
@RequiresPermission(Manifest.permission.MANAGE_ROLE_HOLDERS)
@SystemApi
+ @TestApi
public List<String> getRoleHoldersAsUser(@NonNull String roleName, @NonNull UserHandle user) {
Preconditions.checkStringNotEmpty(roleName, "roleName cannot be null or empty");
Preconditions.checkNotNull(user, "user cannot be null");
@@ -273,6 +276,7 @@
*/
@RequiresPermission(Manifest.permission.MANAGE_ROLE_HOLDERS)
@SystemApi
+ @TestApi
public void addRoleHolderAsUser(@NonNull String roleName, @NonNull String packageName,
@NonNull UserHandle user, @CallbackExecutor @NonNull Executor executor,
@NonNull RoleManagerCallback callback) {
@@ -312,6 +316,7 @@
*/
@RequiresPermission(Manifest.permission.MANAGE_ROLE_HOLDERS)
@SystemApi
+ @TestApi
public void removeRoleHolderAsUser(@NonNull String roleName, @NonNull String packageName,
@NonNull UserHandle user, @CallbackExecutor @NonNull Executor executor,
@NonNull RoleManagerCallback callback) {
@@ -350,6 +355,7 @@
*/
@RequiresPermission(Manifest.permission.MANAGE_ROLE_HOLDERS)
@SystemApi
+ @TestApi
public void clearRoleHoldersAsUser(@NonNull String roleName, @NonNull UserHandle user,
@CallbackExecutor @NonNull Executor executor, @NonNull RoleManagerCallback callback) {
Preconditions.checkStringNotEmpty(roleName, "roleName cannot be null or empty");
diff --git a/core/java/android/app/role/RoleManagerCallback.java b/core/java/android/app/role/RoleManagerCallback.java
index ca68ebc..d9f0a6c 100644
--- a/core/java/android/app/role/RoleManagerCallback.java
+++ b/core/java/android/app/role/RoleManagerCallback.java
@@ -17,6 +17,7 @@
package android.app.role;
import android.annotation.SystemApi;
+import android.annotation.TestApi;
/**
* Callback for a {@link RoleManager} request.
@@ -24,6 +25,7 @@
* @hide
*/
@SystemApi
+@TestApi
public interface RoleManagerCallback {
/**
diff --git a/core/java/android/content/ContentInterface.java b/core/java/android/content/ContentInterface.java
new file mode 100644
index 0000000..3d732eb
--- /dev/null
+++ b/core/java/android/content/ContentInterface.java
@@ -0,0 +1,85 @@
+/*
+ * 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;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.content.res.AssetFileDescriptor;
+import android.database.Cursor;
+import android.net.Uri;
+import android.os.Bundle;
+import android.os.CancellationSignal;
+import android.os.ParcelFileDescriptor;
+import android.os.RemoteException;
+
+import java.io.FileNotFoundException;
+import java.util.ArrayList;
+
+/**
+ * Interface representing calls that can be made to {@link ContentProvider}
+ * instances.
+ * <p>
+ * These methods have been extracted into a general interface so that APIs can
+ * be flexible in accepting either a {@link ContentProvider}, a
+ * {@link ContentResolver}, or a {@link ContentProviderClient}.
+ */
+public interface ContentInterface {
+ public @Nullable Cursor query(@NonNull Uri uri, @Nullable String[] projection,
+ @Nullable Bundle queryArgs, @Nullable CancellationSignal cancellationSignal)
+ throws RemoteException;
+
+ public @Nullable String getType(@NonNull Uri uri) throws RemoteException;
+
+ public @Nullable String[] getStreamTypes(@NonNull Uri uri, @NonNull String mimeTypeFilter)
+ throws RemoteException;
+
+ public @Nullable Uri canonicalize(@NonNull Uri uri) throws RemoteException;
+
+ public @Nullable Uri uncanonicalize(@NonNull Uri uri) throws RemoteException;
+
+ public boolean refresh(@NonNull Uri uri, @Nullable Bundle args,
+ @Nullable CancellationSignal cancellationSignal) throws RemoteException;
+
+ public @Nullable Uri insert(@NonNull Uri uri, @Nullable ContentValues initialValues)
+ throws RemoteException;
+
+ public int bulkInsert(@NonNull Uri uri, @NonNull ContentValues[] initialValues)
+ throws RemoteException;
+
+ public int delete(@NonNull Uri uri, @Nullable String selection,
+ @Nullable String[] selectionArgs) throws RemoteException;
+
+ public int update(@NonNull Uri uri, @Nullable ContentValues values, @Nullable String selection,
+ @Nullable String[] selectionArgs) throws RemoteException;
+
+ public @Nullable ParcelFileDescriptor openFile(@NonNull Uri uri, @NonNull String mode,
+ @Nullable CancellationSignal signal) throws RemoteException, FileNotFoundException;
+
+ public @Nullable AssetFileDescriptor openAssetFile(@NonNull Uri uri, @NonNull String mode,
+ @Nullable CancellationSignal signal) throws RemoteException, FileNotFoundException;
+
+ public @Nullable AssetFileDescriptor openTypedAssetFile(@NonNull Uri uri,
+ @NonNull String mimeTypeFilter, @Nullable Bundle opts,
+ @Nullable CancellationSignal signal) throws RemoteException, FileNotFoundException;
+
+ public @NonNull ContentProviderResult[] applyBatch(@NonNull String authority,
+ @NonNull ArrayList<ContentProviderOperation> operations)
+ throws RemoteException, OperationApplicationException;
+
+ public @Nullable Bundle call(@NonNull String authority, @NonNull String method,
+ @Nullable String arg, @Nullable Bundle extras) throws RemoteException;
+}
diff --git a/core/java/android/content/ContentProvider.java b/core/java/android/content/ContentProvider.java
index 0f72fd3..5a12e4e 100644
--- a/core/java/android/content/ContentProvider.java
+++ b/core/java/android/content/ContentProvider.java
@@ -105,7 +105,7 @@
* developer guide.</p>
* </div>
*/
-public abstract class ContentProvider implements ComponentCallbacks2 {
+public abstract class ContentProvider implements ContentInterface, ComponentCallbacks2 {
private static final String TAG = "ContentProvider";
@@ -324,7 +324,7 @@
}
@Override
- public ContentProviderResult[] applyBatch(String callingPkg,
+ public ContentProviderResult[] applyBatch(String callingPkg, String authority,
ArrayList<ContentProviderOperation> operations)
throws OperationApplicationException {
int numOperations = operations.size();
@@ -356,7 +356,8 @@
Trace.traceBegin(TRACE_TAG_DATABASE, "applyBatch");
final String original = setCallingPackage(callingPkg);
try {
- ContentProviderResult[] results = ContentProvider.this.applyBatch(operations);
+ ContentProviderResult[] results = ContentProvider.this.applyBatch(authority,
+ operations);
if (results != null) {
for (int i = 0; i < results.length ; i++) {
if (userIds[i] != UserHandle.USER_CURRENT) {
@@ -444,13 +445,13 @@
}
@Override
- public Bundle call(
- String callingPkg, String method, @Nullable String arg, @Nullable Bundle extras) {
+ public Bundle call(String callingPkg, String authority, String method, @Nullable String arg,
+ @Nullable Bundle extras) {
Bundle.setDefusable(extras, true);
Trace.traceBegin(TRACE_TAG_DATABASE, "call");
final String original = setCallingPackage(callingPkg);
try {
- return ContentProvider.this.call(method, arg, extras);
+ return ContentProvider.this.call(authority, method, arg, extras);
} finally {
setCallingPackage(original);
Trace.traceEnd(TRACE_TAG_DATABASE);
@@ -1255,6 +1256,7 @@
* or {@code null}.
* @return a Cursor or {@code null}.
*/
+ @Override
public @Nullable Cursor query(@NonNull Uri uri, @Nullable String[] projection,
@Nullable Bundle queryArgs, @Nullable CancellationSignal cancellationSignal) {
queryArgs = queryArgs != null ? queryArgs : Bundle.EMPTY;
@@ -1293,6 +1295,7 @@
* @param uri the URI to query.
* @return a MIME type string, or {@code null} if there is no type.
*/
+ @Override
public abstract @Nullable String getType(@NonNull Uri uri);
/**
@@ -1325,6 +1328,7 @@
* @return Return the canonical representation of <var>url</var>, or null if
* canonicalization of that Uri is not supported.
*/
+ @Override
public @Nullable Uri canonicalize(@NonNull Uri url) {
return null;
}
@@ -1343,6 +1347,7 @@
* the data identified by the canonical representation can not be found in
* the current environment.
*/
+ @Override
public @Nullable Uri uncanonicalize(@NonNull Uri url) {
return url;
}
@@ -1369,6 +1374,7 @@
* canceled the refresh request.
* @return true if the provider actually tried refreshing.
*/
+ @Override
public boolean refresh(Uri uri, @Nullable Bundle args,
@Nullable CancellationSignal cancellationSignal) {
return false;
@@ -1403,6 +1409,7 @@
* This must not be {@code null}.
* @return The URI for the newly inserted item.
*/
+ @Override
public abstract @Nullable Uri insert(@NonNull Uri uri, @Nullable ContentValues values);
/**
@@ -1420,6 +1427,7 @@
* This must not be {@code null}.
* @return The number of values that were inserted.
*/
+ @Override
public int bulkInsert(@NonNull Uri uri, @NonNull ContentValues[] values) {
int numValues = values.length;
for (int i = 0; i < numValues; i++) {
@@ -1448,6 +1456,7 @@
* @return The number of rows affected.
* @throws SQLException
*/
+ @Override
public abstract int delete(@NonNull Uri uri, @Nullable String selection,
@Nullable String[] selectionArgs);
@@ -1468,6 +1477,7 @@
* @param selection An optional filter to match rows to update.
* @return the number of rows affected.
*/
+ @Override
public abstract int update(@NonNull Uri uri, @Nullable ContentValues values,
@Nullable String selection, @Nullable String[] selectionArgs);
@@ -1604,6 +1614,7 @@
* @see #getType(android.net.Uri)
* @see ParcelFileDescriptor#parseMode(String)
*/
+ @Override
public @Nullable ParcelFileDescriptor openFile(@NonNull Uri uri, @NonNull String mode,
@Nullable CancellationSignal signal) throws FileNotFoundException {
return openFile(uri, mode);
@@ -1723,6 +1734,7 @@
* @see #openFileHelper(Uri, String)
* @see #getType(android.net.Uri)
*/
+ @Override
public @Nullable AssetFileDescriptor openAssetFile(@NonNull Uri uri, @NonNull String mode,
@Nullable CancellationSignal signal) throws FileNotFoundException {
return openAssetFile(uri, mode);
@@ -1789,6 +1801,7 @@
* @see #openTypedAssetFile(Uri, String, Bundle)
* @see ClipDescription#compareMimeTypes(String, String)
*/
+ @Override
public @Nullable String[] getStreamTypes(@NonNull Uri uri, @NonNull String mimeTypeFilter) {
return null;
}
@@ -1905,6 +1918,7 @@
* @see #openAssetFile(Uri, String)
* @see ClipDescription#compareMimeTypes(String, String)
*/
+ @Override
public @Nullable AssetFileDescriptor openTypedAssetFile(@NonNull Uri uri,
@NonNull String mimeTypeFilter, @Nullable Bundle opts,
@Nullable CancellationSignal signal) throws FileNotFoundException {
@@ -2059,6 +2073,13 @@
* @throws OperationApplicationException thrown if any operation fails.
* @see ContentProviderOperation#apply
*/
+ @Override
+ public @NonNull ContentProviderResult[] applyBatch(@NonNull String authority,
+ @NonNull ArrayList<ContentProviderOperation> operations)
+ throws OperationApplicationException {
+ return applyBatch(operations);
+ }
+
public @NonNull ContentProviderResult[] applyBatch(
@NonNull ArrayList<ContentProviderOperation> operations)
throws OperationApplicationException {
@@ -2088,6 +2109,12 @@
* @return provider-defined return value. May be {@code null}, which is also
* the default for providers which don't implement any call methods.
*/
+ @Override
+ public @Nullable Bundle call(@NonNull String authority, @NonNull String method,
+ @Nullable String arg, @Nullable Bundle extras) {
+ return call(method, arg, extras);
+ }
+
public @Nullable Bundle call(@NonNull String method, @Nullable String arg,
@Nullable Bundle extras) {
return null;
@@ -2133,6 +2160,19 @@
writer.println("nothing to dump");
}
+ private void validateIncomingAuthority(String authority) throws SecurityException {
+ if (!matchesOurAuthorities(getAuthorityWithoutUserId(authority))) {
+ String message = "The authority " + authority + " does not match the one of the "
+ + "contentProvider: ";
+ if (mAuthority != null) {
+ message += mAuthority;
+ } else {
+ message += Arrays.toString(mAuthorities);
+ }
+ throw new SecurityException(message);
+ }
+ }
+
/** @hide */
@VisibleForTesting
public Uri validateIncomingUri(Uri uri) throws SecurityException {
@@ -2144,16 +2184,7 @@
+ mContext.getUserId() + " with a uri belonging to user " + userId);
}
}
- if (!matchesOurAuthorities(getAuthorityWithoutUserId(auth))) {
- String message = "The authority of the uri " + uri + " does not match the one of the "
- + "contentProvider: ";
- if (mAuthority != null) {
- message += mAuthority;
- } else {
- message += Arrays.toString(mAuthorities);
- }
- throw new SecurityException(message);
- }
+ validateIncomingAuthority(auth);
// Normalize the path by removing any empty path segments, which can be
// a source of security issues.
diff --git a/core/java/android/content/ContentProviderClient.java b/core/java/android/content/ContentProviderClient.java
index d315f49..0b5bdb5 100644
--- a/core/java/android/content/ContentProviderClient.java
+++ b/core/java/android/content/ContentProviderClient.java
@@ -16,8 +16,12 @@
package android.content;
+import android.annotation.DurationMillisLong;
import android.annotation.NonNull;
import android.annotation.Nullable;
+import android.annotation.RequiresPermission;
+import android.annotation.SystemApi;
+import android.annotation.TestApi;
import android.annotation.UnsupportedAppUsage;
import android.content.res.AssetFileDescriptor;
import android.database.CrossProcessCursorWrapper;
@@ -65,7 +69,7 @@
* on the ContentProviderClient those calls are made from until you are finished
* with the data they have returned.
*/
-public class ContentProviderClient implements AutoCloseable {
+public class ContentProviderClient implements ContentInterface, AutoCloseable {
private static final String TAG = "ContentProviderClient";
@GuardedBy("ContentProviderClient.class")
@@ -76,6 +80,7 @@
private final IContentProvider mContentProvider;
@UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
private final String mPackageName;
+ private final String mAuthority;
private final boolean mStable;
private final AtomicBoolean mClosed = new AtomicBoolean();
@@ -86,19 +91,39 @@
/** {@hide} */
@VisibleForTesting
- public ContentProviderClient(
- ContentResolver contentResolver, IContentProvider contentProvider, boolean stable) {
+ public ContentProviderClient(ContentResolver contentResolver, IContentProvider contentProvider,
+ boolean stable) {
+ // Only used for testing, so use a fake authority
+ this(contentResolver, contentProvider, "unknown", stable);
+ }
+
+ /** {@hide} */
+ public ContentProviderClient(ContentResolver contentResolver, IContentProvider contentProvider,
+ String authority, boolean stable) {
mContentResolver = contentResolver;
mContentProvider = contentProvider;
mPackageName = contentResolver.mPackageName;
+ mAuthority = authority;
mStable = stable;
mCloseGuard.open("close");
}
- /** {@hide} */
- public void setDetectNotResponding(long timeoutMillis) {
+ /**
+ * Configure this client to automatically detect and kill the remote
+ * provider when an "application not responding" event is detected.
+ *
+ * @param timeoutMillis the duration for which a pending call is allowed
+ * block before the remote provider is considered to be
+ * unresponsive. Set to {@code 0} to allow pending calls to block
+ * indefinitely with no action taken.
+ * @hide
+ */
+ @SystemApi
+ @TestApi
+ @RequiresPermission(android.Manifest.permission.REMOVE_TASKS)
+ public void setDetectNotResponding(@DurationMillisLong long timeoutMillis) {
synchronized (ContentProviderClient.class) {
mAnrTimeout = timeoutMillis;
@@ -153,6 +178,7 @@
}
/** See {@link ContentProvider#query ContentProvider.query} */
+ @Override
public @Nullable Cursor query(@NonNull Uri uri, @Nullable String[] projection,
Bundle queryArgs, @Nullable CancellationSignal cancellationSignal)
throws RemoteException {
@@ -183,6 +209,7 @@
}
/** See {@link ContentProvider#getType ContentProvider.getType} */
+ @Override
public @Nullable String getType(@NonNull Uri url) throws RemoteException {
Preconditions.checkNotNull(url, "url");
@@ -200,6 +227,7 @@
}
/** See {@link ContentProvider#getStreamTypes ContentProvider.getStreamTypes} */
+ @Override
public @Nullable String[] getStreamTypes(@NonNull Uri url, @NonNull String mimeTypeFilter)
throws RemoteException {
Preconditions.checkNotNull(url, "url");
@@ -219,6 +247,7 @@
}
/** See {@link ContentProvider#canonicalize} */
+ @Override
public final @Nullable Uri canonicalize(@NonNull Uri url) throws RemoteException {
Preconditions.checkNotNull(url, "url");
@@ -236,6 +265,7 @@
}
/** See {@link ContentProvider#uncanonicalize} */
+ @Override
public final @Nullable Uri uncanonicalize(@NonNull Uri url) throws RemoteException {
Preconditions.checkNotNull(url, "url");
@@ -253,6 +283,7 @@
}
/** See {@link ContentProvider#refresh} */
+ @Override
public boolean refresh(Uri url, @Nullable Bundle args,
@Nullable CancellationSignal cancellationSignal) throws RemoteException {
Preconditions.checkNotNull(url, "url");
@@ -277,6 +308,7 @@
}
/** See {@link ContentProvider#insert ContentProvider.insert} */
+ @Override
public @Nullable Uri insert(@NonNull Uri url, @Nullable ContentValues initialValues)
throws RemoteException {
Preconditions.checkNotNull(url, "url");
@@ -295,6 +327,7 @@
}
/** See {@link ContentProvider#bulkInsert ContentProvider.bulkInsert} */
+ @Override
public int bulkInsert(@NonNull Uri url, @NonNull ContentValues[] initialValues)
throws RemoteException {
Preconditions.checkNotNull(url, "url");
@@ -314,6 +347,7 @@
}
/** See {@link ContentProvider#delete ContentProvider.delete} */
+ @Override
public int delete(@NonNull Uri url, @Nullable String selection,
@Nullable String[] selectionArgs) throws RemoteException {
Preconditions.checkNotNull(url, "url");
@@ -332,6 +366,7 @@
}
/** See {@link ContentProvider#update ContentProvider.update} */
+ @Override
public int update(@NonNull Uri url, @Nullable ContentValues values, @Nullable String selection,
@Nullable String[] selectionArgs) throws RemoteException {
Preconditions.checkNotNull(url, "url");
@@ -368,6 +403,7 @@
* you use the {@link ContentResolver#openFileDescriptor
* ContentResolver.openFileDescriptor} API instead.
*/
+ @Override
public @Nullable ParcelFileDescriptor openFile(@NonNull Uri url, @NonNull String mode,
@Nullable CancellationSignal signal) throws RemoteException, FileNotFoundException {
Preconditions.checkNotNull(url, "url");
@@ -411,6 +447,7 @@
* you use the {@link ContentResolver#openAssetFileDescriptor
* ContentResolver.openAssetFileDescriptor} API instead.
*/
+ @Override
public @Nullable AssetFileDescriptor openAssetFile(@NonNull Uri url, @NonNull String mode,
@Nullable CancellationSignal signal) throws RemoteException, FileNotFoundException {
Preconditions.checkNotNull(url, "url");
@@ -446,8 +483,15 @@
public final @Nullable AssetFileDescriptor openTypedAssetFileDescriptor(@NonNull Uri uri,
@NonNull String mimeType, @Nullable Bundle opts, @Nullable CancellationSignal signal)
throws RemoteException, FileNotFoundException {
+ return openTypedAssetFile(uri, mimeType, opts, signal);
+ }
+
+ @Override
+ public final @Nullable AssetFileDescriptor openTypedAssetFile(@NonNull Uri uri,
+ @NonNull String mimeTypeFilter, @Nullable Bundle opts,
+ @Nullable CancellationSignal signal) throws RemoteException, FileNotFoundException {
Preconditions.checkNotNull(uri, "uri");
- Preconditions.checkNotNull(mimeType, "mimeType");
+ Preconditions.checkNotNull(mimeTypeFilter, "mimeTypeFilter");
beforeRemote();
try {
@@ -458,7 +502,7 @@
signal.setRemote(remoteSignal);
}
return mContentProvider.openTypedAssetFile(
- mPackageName, uri, mimeType, opts, remoteSignal);
+ mPackageName, uri, mimeTypeFilter, opts, remoteSignal);
} catch (DeadObjectException e) {
if (!mStable) {
mContentResolver.unstableProviderDied(mContentProvider);
@@ -472,12 +516,20 @@
/** See {@link ContentProvider#applyBatch ContentProvider.applyBatch} */
public @NonNull ContentProviderResult[] applyBatch(
@NonNull ArrayList<ContentProviderOperation> operations)
- throws RemoteException, OperationApplicationException {
+ throws RemoteException, OperationApplicationException {
+ return applyBatch(mAuthority, operations);
+ }
+
+ /** See {@link ContentProvider#applyBatch ContentProvider.applyBatch} */
+ @Override
+ public @NonNull ContentProviderResult[] applyBatch(@NonNull String authority,
+ @NonNull ArrayList<ContentProviderOperation> operations)
+ throws RemoteException, OperationApplicationException {
Preconditions.checkNotNull(operations, "operations");
beforeRemote();
try {
- return mContentProvider.applyBatch(mPackageName, operations);
+ return mContentProvider.applyBatch(mPackageName, authority, operations);
} catch (DeadObjectException e) {
if (!mStable) {
mContentResolver.unstableProviderDied(mContentProvider);
@@ -491,11 +543,19 @@
/** See {@link ContentProvider#call(String, String, Bundle)} */
public @Nullable Bundle call(@NonNull String method, @Nullable String arg,
@Nullable Bundle extras) throws RemoteException {
+ return call(mAuthority, method, arg, extras);
+ }
+
+ /** See {@link ContentProvider#call(String, String, Bundle)} */
+ @Override
+ public @Nullable Bundle call(@NonNull String authority, @NonNull String method,
+ @Nullable String arg, @Nullable Bundle extras) throws RemoteException {
+ Preconditions.checkNotNull(authority, "authority");
Preconditions.checkNotNull(method, "method");
beforeRemote();
try {
- return mContentProvider.call(mPackageName, method, arg, extras);
+ return mContentProvider.call(mPackageName, authority, method, arg, extras);
} catch (DeadObjectException e) {
if (!mStable) {
mContentResolver.unstableProviderDied(mContentProvider);
diff --git a/core/java/android/content/ContentProviderNative.java b/core/java/android/content/ContentProviderNative.java
index 6bede13..ca657b1 100644
--- a/core/java/android/content/ContentProviderNative.java
+++ b/core/java/android/content/ContentProviderNative.java
@@ -174,13 +174,15 @@
{
data.enforceInterface(IContentProvider.descriptor);
String callingPkg = data.readString();
+ String authority = data.readString();
final int numOperations = data.readInt();
final ArrayList<ContentProviderOperation> operations =
new ArrayList<>(numOperations);
for (int i = 0; i < numOperations; i++) {
operations.add(i, ContentProviderOperation.CREATOR.createFromParcel(data));
}
- final ContentProviderResult[] results = applyBatch(callingPkg, operations);
+ final ContentProviderResult[] results = applyBatch(callingPkg, authority,
+ operations);
reply.writeNoException();
reply.writeTypedArray(results, 0);
return true;
@@ -267,11 +269,12 @@
data.enforceInterface(IContentProvider.descriptor);
String callingPkg = data.readString();
+ String authority = data.readString();
String method = data.readString();
String stringArg = data.readString();
Bundle args = data.readBundle();
- Bundle responseBundle = call(callingPkg, method, stringArg, args);
+ Bundle responseBundle = call(callingPkg, authority, method, stringArg, args);
reply.writeNoException();
reply.writeBundle(responseBundle);
@@ -507,7 +510,7 @@
}
@Override
- public ContentProviderResult[] applyBatch(String callingPkg,
+ public ContentProviderResult[] applyBatch(String callingPkg, String authority,
ArrayList<ContentProviderOperation> operations)
throws RemoteException, OperationApplicationException {
Parcel data = Parcel.obtain();
@@ -515,6 +518,7 @@
try {
data.writeInterfaceToken(IContentProvider.descriptor);
data.writeString(callingPkg);
+ data.writeString(authority);
data.writeInt(operations.size());
for (ContentProviderOperation operation : operations) {
operation.writeToParcel(data, 0);
@@ -636,14 +640,15 @@
}
@Override
- public Bundle call(String callingPkg, String method, String request, Bundle args)
- throws RemoteException {
+ public Bundle call(String callingPkg, String authority, String method, String request,
+ Bundle args) throws RemoteException {
Parcel data = Parcel.obtain();
Parcel reply = Parcel.obtain();
try {
data.writeInterfaceToken(IContentProvider.descriptor);
data.writeString(callingPkg);
+ data.writeString(authority);
data.writeString(method);
data.writeString(request);
data.writeBundle(args);
diff --git a/core/java/android/content/ContentResolver.java b/core/java/android/content/ContentResolver.java
index 7d5202d..da65941 100644
--- a/core/java/android/content/ContentResolver.java
+++ b/core/java/android/content/ContentResolver.java
@@ -52,7 +52,6 @@
import android.os.RemoteException;
import android.os.ServiceManager;
import android.os.SystemClock;
-import android.os.SystemProperties;
import android.os.UserHandle;
import android.os.storage.StorageManager;
import android.text.TextUtils;
@@ -88,7 +87,7 @@
* <a href="{@docRoot}guide/topics/providers/content-providers.html">Content Providers</a>
* developer guide.</p>
*/
-public abstract class ContentResolver {
+public abstract class ContentResolver implements ContentInterface {
/**
* Enables logic that supports deprecation of {@code _data} columns,
* typically by replacing values with fake paths that the OS then offers to
@@ -655,6 +654,7 @@
* using the content:// scheme.
* @return A MIME type for the content, or null if the URL is invalid or the type is unknown
*/
+ @Override
public final @Nullable String getType(@NonNull Uri url) {
Preconditions.checkNotNull(url, "url");
@@ -708,6 +708,7 @@
* data streams that match the given mimeTypeFilter. If there are none,
* null is returned.
*/
+ @Override
public @Nullable String[] getStreamTypes(@NonNull Uri url, @NonNull String mimeTypeFilter) {
Preconditions.checkNotNull(url, "url");
Preconditions.checkNotNull(mimeTypeFilter, "mimeTypeFilter");
@@ -835,6 +836,7 @@
* @return A Cursor object, which is positioned before the first entry, or null
* @see Cursor
*/
+ @Override
public final @Nullable Cursor query(final @RequiresPermission.Read @NonNull Uri uri,
@Nullable String[] projection, @Nullable Bundle queryArgs,
@Nullable CancellationSignal cancellationSignal) {
@@ -935,6 +937,7 @@
*
* @see #uncanonicalize
*/
+ @Override
public final @Nullable Uri canonicalize(@NonNull Uri url) {
Preconditions.checkNotNull(url, "url");
IContentProvider provider = acquireProvider(url);
@@ -971,6 +974,7 @@
*
* @see #canonicalize
*/
+ @Override
public final @Nullable Uri uncanonicalize(@NonNull Uri url) {
Preconditions.checkNotNull(url, "url");
IContentProvider provider = acquireProvider(url);
@@ -1005,6 +1009,7 @@
* canceled the refresh request.
* @return true if the provider actually tried refreshing.
*/
+ @Override
public final boolean refresh(@NonNull Uri url, @Nullable Bundle args,
@Nullable CancellationSignal cancellationSignal) {
Preconditions.checkNotNull(url, "url");
@@ -1116,6 +1121,12 @@
}
}
+ @Override
+ public final @Nullable ParcelFileDescriptor openFile(@NonNull Uri uri, @NonNull String mode,
+ @Nullable CancellationSignal signal) throws FileNotFoundException {
+ return openFileDescriptor(uri, mode, signal);
+ }
+
/**
* Open a raw file descriptor to access data under a URI. This
* is like {@link #openAssetFileDescriptor(Uri, String)}, but uses the
@@ -1221,6 +1232,12 @@
throw new FileNotFoundException("Not a whole file");
}
+ @Override
+ public final @Nullable AssetFileDescriptor openAssetFile(@NonNull Uri uri, @NonNull String mode,
+ @Nullable CancellationSignal signal) throws FileNotFoundException {
+ return openAssetFileDescriptor(uri, mode, signal);
+ }
+
/**
* Open a raw file descriptor to access data under a URI. This
* interacts with the underlying {@link ContentProvider#openAssetFile}
@@ -1425,6 +1442,13 @@
}
}
+ @Override
+ public final @Nullable AssetFileDescriptor openTypedAssetFile(@NonNull Uri uri,
+ @NonNull String mimeTypeFilter, @Nullable Bundle opts,
+ @Nullable CancellationSignal signal) throws FileNotFoundException {
+ return openTypedAssetFileDescriptor(uri, mimeTypeFilter, opts, signal);
+ }
+
/**
* Open a raw file descriptor to access (potentially type transformed)
* data from a "content:" URI. This interacts with the underlying
@@ -1634,6 +1658,7 @@
* the field. Passing an empty ContentValues will create an empty row.
* @return the URL of the newly created row.
*/
+ @Override
public final @Nullable Uri insert(@RequiresPermission.Write @NonNull Uri url,
@Nullable ContentValues values) {
Preconditions.checkNotNull(url, "url");
@@ -1672,6 +1697,7 @@
* @throws RemoteException thrown if a RemoteException is encountered while attempting
* to communicate with a remote provider.
*/
+ @Override
public @NonNull ContentProviderResult[] applyBatch(@NonNull String authority,
@NonNull ArrayList<ContentProviderOperation> operations)
throws RemoteException, OperationApplicationException {
@@ -1698,6 +1724,7 @@
* the field. Passing null will create an empty row.
* @return the number of newly created rows.
*/
+ @Override
public final int bulkInsert(@RequiresPermission.Write @NonNull Uri url,
@NonNull ContentValues[] values) {
Preconditions.checkNotNull(url, "url");
@@ -1731,6 +1758,7 @@
(excluding the WHERE itself).
* @return The number of rows deleted.
*/
+ @Override
public final int delete(@RequiresPermission.Write @NonNull Uri url, @Nullable String where,
@Nullable String[] selectionArgs) {
Preconditions.checkNotNull(url, "url");
@@ -1766,6 +1794,7 @@
* @return the number of rows updated.
* @throws NullPointerException if uri or values are null
*/
+ @Override
public final int update(@RequiresPermission.Write @NonNull Uri uri,
@Nullable ContentValues values, @Nullable String where,
@Nullable String[] selectionArgs) {
@@ -1805,14 +1834,20 @@
*/
public final @Nullable Bundle call(@NonNull Uri uri, @NonNull String method,
@Nullable String arg, @Nullable Bundle extras) {
- Preconditions.checkNotNull(uri, "uri");
+ return call(uri.getAuthority(), method, arg, extras);
+ }
+
+ @Override
+ public final @Nullable Bundle call(@NonNull String authority, @NonNull String method,
+ @Nullable String arg, @Nullable Bundle extras) {
+ Preconditions.checkNotNull(authority, "authority");
Preconditions.checkNotNull(method, "method");
- IContentProvider provider = acquireProvider(uri);
+ IContentProvider provider = acquireProvider(authority);
if (provider == null) {
- throw new IllegalArgumentException("Unknown URI " + uri);
+ throw new IllegalArgumentException("Unknown authority " + authority);
}
try {
- final Bundle res = provider.call(mPackageName, method, arg, extras);
+ final Bundle res = provider.call(mPackageName, authority, method, arg, extras);
Bundle.setDefusable(res, true);
return res;
} catch (RemoteException e) {
@@ -1918,7 +1953,7 @@
Preconditions.checkNotNull(uri, "uri");
IContentProvider provider = acquireProvider(uri);
if (provider != null) {
- return new ContentProviderClient(this, provider, true);
+ return new ContentProviderClient(this, provider, uri.getAuthority(), true);
}
return null;
}
@@ -1939,7 +1974,7 @@
Preconditions.checkNotNull(name, "name");
IContentProvider provider = acquireProvider(name);
if (provider != null) {
- return new ContentProviderClient(this, provider, true);
+ return new ContentProviderClient(this, provider, name, true);
}
return null;
@@ -1966,7 +2001,7 @@
Preconditions.checkNotNull(uri, "uri");
IContentProvider provider = acquireUnstableProvider(uri);
if (provider != null) {
- return new ContentProviderClient(this, provider, false);
+ return new ContentProviderClient(this, provider, uri.getAuthority(), false);
}
return null;
@@ -1993,7 +2028,7 @@
Preconditions.checkNotNull(name, "name");
IContentProvider provider = acquireUnstableProvider(name);
if (provider != null) {
- return new ContentProviderClient(this, provider, false);
+ return new ContentProviderClient(this, provider, name, false);
}
return null;
@@ -3248,10 +3283,10 @@
}
/** {@hide} */
- public static Bitmap loadThumbnail(@NonNull ContentProviderClient client, @NonNull Uri uri,
+ public static Bitmap loadThumbnail(@NonNull ContentInterface content, @NonNull Uri uri,
@NonNull Size size, @Nullable CancellationSignal signal, int allocator)
throws IOException {
- Objects.requireNonNull(client);
+ Objects.requireNonNull(content);
Objects.requireNonNull(uri);
Objects.requireNonNull(size);
@@ -3260,7 +3295,7 @@
opts.putParcelable(EXTRA_SIZE, Point.convert(size));
return ImageDecoder.decodeBitmap(ImageDecoder.createSource(() -> {
- return client.openTypedAssetFileDescriptor(uri, "image/*", opts, signal);
+ return content.openTypedAssetFile(uri, "image/*", opts, signal);
}), (ImageDecoder decoder, ImageInfo info, Source source) -> {
decoder.setAllocator(allocator);
diff --git a/core/java/android/content/IContentProvider.java b/core/java/android/content/IContentProvider.java
index 044ed61..0427c2f 100644
--- a/core/java/android/content/IContentProvider.java
+++ b/core/java/android/content/IContentProvider.java
@@ -60,13 +60,28 @@
public AssetFileDescriptor openAssetFile(
String callingPkg, Uri url, String mode, ICancellationSignal signal)
throws RemoteException, FileNotFoundException;
- public ContentProviderResult[] applyBatch(String callingPkg,
+
+ @Deprecated
+ public default ContentProviderResult[] applyBatch(String callingPkg,
ArrayList<ContentProviderOperation> operations)
- throws RemoteException, OperationApplicationException;
+ throws RemoteException, OperationApplicationException {
+ return applyBatch(callingPkg, "unknown", operations);
+ }
+
+ public ContentProviderResult[] applyBatch(String callingPkg, String authority,
+ ArrayList<ContentProviderOperation> operations)
+ throws RemoteException, OperationApplicationException;
+
+ @Deprecated
@UnsupportedAppUsage
- public Bundle call(
- String callingPkg, String method, @Nullable String arg, @Nullable Bundle extras)
- throws RemoteException;
+ public default Bundle call(String callingPkg, String method,
+ @Nullable String arg, @Nullable Bundle extras) throws RemoteException {
+ return call(callingPkg, "unknown", method, arg, extras);
+ }
+
+ public Bundle call(String callingPkg, String authority, String method,
+ @Nullable String arg, @Nullable Bundle extras) throws RemoteException;
+
public ICancellationSignal createCancellationSignal() throws RemoteException;
public Uri canonicalize(String callingPkg, Uri uri) throws RemoteException;
diff --git a/core/java/android/content/pm/IPackageManager.aidl b/core/java/android/content/pm/IPackageManager.aidl
index dbea821..eea2b88 100644
--- a/core/java/android/content/pm/IPackageManager.aidl
+++ b/core/java/android/content/pm/IPackageManager.aidl
@@ -675,6 +675,8 @@
String getSystemTextClassifierPackageName();
+ String getWellbeingPackageName();
+
boolean isPackageStateProtected(String packageName, int userId);
void sendDeviceCustomizationReadyBroadcast();
diff --git a/core/java/android/content/pm/PackageManager.java b/core/java/android/content/pm/PackageManager.java
index b7df2bf..0150f6a 100644
--- a/core/java/android/content/pm/PackageManager.java
+++ b/core/java/android/content/pm/PackageManager.java
@@ -2687,6 +2687,16 @@
"android.software.device_id_attestation";
/**
+ * Feature for {@link #getSystemAvailableFeatures} and {@link #hasSystemFeature}: The device has
+ * the requisite kernel support for multinetworking-capable IPsec tunnels.
+ *
+ * <p>This feature implies that the device supports XFRM Interfaces (CONFIG_XFRM_INTERFACE), or
+ * VTIs with kernel patches allowing updates of output/set mark via UPDSA.
+ */
+ @SdkConstant(SdkConstantType.FEATURE)
+ public static final String FEATURE_IPSEC_TUNNELS = "android.software.ipsec_tunnels";
+
+ /**
* Extra field name for the URI to a verification file. Passed to a package
* verifier.
*
@@ -6424,6 +6434,17 @@
}
/**
+ * @return the wellbeing app package name, or null if it's not defined by the OEM.
+ *
+ * @hide
+ */
+ @SystemApi
+ public String getWellbeingPackageName() {
+ throw new UnsupportedOperationException(
+ "getWellbeingPackageName not implemented in subclass");
+ }
+
+ /**
* @return whether a given package's state is protected, e.g. package cannot be disabled,
* suspended, hidden or force stopped.
*
diff --git a/core/java/android/content/pm/PackageManagerInternal.java b/core/java/android/content/pm/PackageManagerInternal.java
index b49c447..43c0222 100644
--- a/core/java/android/content/pm/PackageManagerInternal.java
+++ b/core/java/android/content/pm/PackageManagerInternal.java
@@ -53,6 +53,7 @@
public static final int PACKAGE_BROWSER = 4;
public static final int PACKAGE_SYSTEM_TEXT_CLASSIFIER = 5;
public static final int PACKAGE_PERMISSION_CONTROLLER = 6;
+ public static final int PACKAGE_WELLBEING = 7;
@IntDef(value = {
PACKAGE_SYSTEM,
PACKAGE_SETUP_WIZARD,
@@ -61,6 +62,7 @@
PACKAGE_BROWSER,
PACKAGE_SYSTEM_TEXT_CLASSIFIER,
PACKAGE_PERMISSION_CONTROLLER,
+ PACKAGE_WELLBEING,
})
@Retention(RetentionPolicy.SOURCE)
public @interface KnownPackage {}
diff --git a/core/java/android/content/pm/PackageParser.java b/core/java/android/content/pm/PackageParser.java
index ac18dca..d0de9a1 100644
--- a/core/java/android/content/pm/PackageParser.java
+++ b/core/java/android/content/pm/PackageParser.java
@@ -5380,6 +5380,10 @@
s.info.splitName =
sa.getNonConfigurationString(R.styleable.AndroidManifestService_splitName, 0);
+ s.info.mForegroundServiceType = sa.getInt(
+ com.android.internal.R.styleable.AndroidManifestService_foregroundServiceType,
+ ServiceInfo.FOREGROUND_SERVICE_TYPE_UNSPECIFIED);
+
s.info.flags = 0;
if (sa.getBoolean(
com.android.internal.R.styleable.AndroidManifestService_stopWithTask,
diff --git a/core/java/android/content/pm/PermissionInfo.java b/core/java/android/content/pm/PermissionInfo.java
index d9d6b5f..20997d6 100644
--- a/core/java/android/content/pm/PermissionInfo.java
+++ b/core/java/android/content/pm/PermissionInfo.java
@@ -181,6 +181,17 @@
@TestApi
public static final int PROTECTION_FLAG_SYSTEM_TEXT_CLASSIFIER = 0x10000;
+ /**
+ * Additional flag for {${link #protectionLevel}, corresponding
+ * to the <code>wellbeing</code> value of
+ * {@link android.R.attr#protectionLevel}.
+ *
+ * @hide
+ */
+ @SystemApi
+ @TestApi
+ public static final int PROTECTION_FLAG_WELLBEING = 0x20000;
+
/** @hide */
@IntDef(flag = true, prefix = { "PROTECTION_FLAG_" }, value = {
PROTECTION_FLAG_PRIVILEGED,
@@ -197,6 +208,7 @@
PROTECTION_FLAG_OEM,
PROTECTION_FLAG_VENDOR_PRIVILEGED,
PROTECTION_FLAG_SYSTEM_TEXT_CLASSIFIER,
+ PROTECTION_FLAG_WELLBEING,
})
@Retention(RetentionPolicy.SOURCE)
public @interface ProtectionFlags {}
@@ -386,6 +398,9 @@
if ((level & PermissionInfo.PROTECTION_FLAG_SYSTEM_TEXT_CLASSIFIER) != 0) {
protLevel += "|textClassifier";
}
+ if ((level & PermissionInfo.PROTECTION_FLAG_WELLBEING) != 0) {
+ protLevel += "|wellbeing";
+ }
return protLevel;
}
diff --git a/core/java/android/content/pm/ServiceInfo.java b/core/java/android/content/pm/ServiceInfo.java
index ad2c72274..8300c0c 100644
--- a/core/java/android/content/pm/ServiceInfo.java
+++ b/core/java/android/content/pm/ServiceInfo.java
@@ -16,10 +16,14 @@
package android.content.pm;
+import android.annotation.IntDef;
import android.os.Parcel;
import android.os.Parcelable;
import android.util.Printer;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+
/**
* Information you can retrieve about a particular application
* service. This corresponds to information collected from the
@@ -94,6 +98,81 @@
*/
public int flags;
+ /**
+ * The default foreground service type if not been set in manifest file.
+ */
+ public static final int FOREGROUND_SERVICE_TYPE_UNSPECIFIED = 0;
+
+ /**
+ * Constant corresponding to <code>sync</code> in
+ * the {@link android.R.attr#foregroundServiceType} attribute.
+ * Data(photo, file, account) upload/download, backup/restore, import/export, fetch,
+ * transfer over network between device and cloud.
+ */
+ public static final int FOREGROUND_SERVICE_TYPE_SYNC = 1;
+
+ /**
+ * Constant corresponding to <code>mediaPlay</code> in
+ * the {@link android.R.attr#foregroundServiceType} attribute.
+ * Music, video, news or other media play.
+ */
+ public static final int FOREGROUND_SERVICE_TYPE_MEDIA_PLAY = 2;
+
+ /**
+ * Constant corresponding to <code>phoneCall</code> in
+ * the {@link android.R.attr#foregroundServiceType} attribute.
+ * Ongoing phone call or video conference.
+ */
+ public static final int FOREGROUND_SERVICE_TYPE_PHONE_CALL = 3;
+
+ /**
+ * Constant corresponding to <code>location</code> in
+ * the {@link android.R.attr#foregroundServiceType} attribute.
+ * GPS, map, navigation location update.
+ */
+ public static final int FOREGROUND_SERVICE_TYPE_LOCATION = 4;
+
+ /**
+ * Constant corresponding to <code>deviceCompanion</code> in
+ * the {@link android.R.attr#foregroundServiceType} attribute.
+ * Auto, bluetooth, TV or other devices connection, monitoring and interaction.
+ */
+ public static final int FOREGROUND_SERVICE_TYPE_DEVICE_COMPANION = 5;
+
+ /**
+ * Constant corresponding to <code>ongoingProcess</code> in
+ * the {@link android.R.attr#foregroundServiceType} attribute.
+ * Process that should not be interrupted, including installation, setup, photo
+ * compression etc.
+ */
+ public static final int FOREGROUND_SERVICE_TYPE_ONGOING_PROCESS = 6;
+
+ /**
+ * The enumeration of values for foreground service type.
+ * The foreground service type is set in {@link android.R.attr#foregroundServiceType}
+ * attribute.
+ * @hide
+ */
+ @IntDef(flag = false, prefix = { "FOREGROUND_SERVICE_TYPE_" }, value = {
+ FOREGROUND_SERVICE_TYPE_UNSPECIFIED,
+ FOREGROUND_SERVICE_TYPE_SYNC,
+ FOREGROUND_SERVICE_TYPE_MEDIA_PLAY,
+ FOREGROUND_SERVICE_TYPE_PHONE_CALL,
+ FOREGROUND_SERVICE_TYPE_LOCATION,
+ FOREGROUND_SERVICE_TYPE_DEVICE_COMPANION,
+ FOREGROUND_SERVICE_TYPE_ONGOING_PROCESS
+ })
+ @Retention(RetentionPolicy.SOURCE)
+ public @interface ForegroundServiceType {}
+
+ /**
+ * The type of foreground service, set in
+ * {@link android.R.attr#foregroundServiceType} attribute, one value in
+ * {@link ForegroundServiceType}
+ * @hide
+ */
+ public @ForegroundServiceType int mForegroundServiceType = FOREGROUND_SERVICE_TYPE_UNSPECIFIED;
+
public ServiceInfo() {
}
@@ -101,6 +180,15 @@
super(orig);
permission = orig.permission;
flags = orig.flags;
+ mForegroundServiceType = orig.mForegroundServiceType;
+ }
+
+ /**
+ * Return the current foreground service type.
+ * @return the current foreground service type.
+ */
+ public int getForegroundServiceType() {
+ return mForegroundServiceType;
}
public void dump(Printer pw, String prefix) {
diff --git a/core/java/android/content/pm/permission/IRuntimePermissionPresenter.aidl b/core/java/android/content/pm/permission/IRuntimePermissionPresenter.aidl
index 9490e27..2faf3ad 100644
--- a/core/java/android/content/pm/permission/IRuntimePermissionPresenter.aidl
+++ b/core/java/android/content/pm/permission/IRuntimePermissionPresenter.aidl
@@ -22,6 +22,8 @@
* Interface for communication with the permission presenter service.
*
* @hide
+ * @deprecated Only available to keep
+ * android.permissionpresenterservice.RuntimePermissionPresenterService functional
*/
oneway interface IRuntimePermissionPresenter {
void getAppPermissions(String packageName, in RemoteCallback callback);
diff --git a/core/java/android/content/pm/permission/RuntimePermissionPresentationInfo.java b/core/java/android/content/pm/permission/RuntimePermissionPresentationInfo.java
index 352e8ad..9fa863c 100644
--- a/core/java/android/content/pm/permission/RuntimePermissionPresentationInfo.java
+++ b/core/java/android/content/pm/permission/RuntimePermissionPresentationInfo.java
@@ -29,7 +29,11 @@
* coarse and fine platform permissions.
*
* @hide
+ *
+ * @deprecated Not used anymore. Use {@link android.permission.RuntimePermissionPresentationInfo}
+ * instead
*/
+@Deprecated
@SystemApi
public final class RuntimePermissionPresentationInfo implements Parcelable {
private static final int FLAG_GRANTED = 1 << 0;
diff --git a/core/java/android/net/NetworkCapabilities.java b/core/java/android/net/NetworkCapabilities.java
index 0bdfca7..0c44a56 100644
--- a/core/java/android/net/NetworkCapabilities.java
+++ b/core/java/android/net/NetworkCapabilities.java
@@ -17,6 +17,7 @@
package android.net;
import android.annotation.IntDef;
+import android.annotation.Nullable;
import android.annotation.SystemApi;
import android.annotation.TestApi;
import android.annotation.UnsupportedAppUsage;
@@ -79,6 +80,7 @@
mNetworkCapabilities = mTransportTypes = mUnwantedNetworkCapabilities = 0;
mLinkUpBandwidthKbps = mLinkDownBandwidthKbps = LINK_BANDWIDTH_UNSPECIFIED;
mNetworkSpecifier = null;
+ mTransportInfo = null;
mSignalStrength = SIGNAL_STRENGTH_UNSPECIFIED;
mUids = null;
mEstablishingVpnAppUid = INVALID_UID;
@@ -95,6 +97,7 @@
mLinkUpBandwidthKbps = nc.mLinkUpBandwidthKbps;
mLinkDownBandwidthKbps = nc.mLinkDownBandwidthKbps;
mNetworkSpecifier = nc.mNetworkSpecifier;
+ mTransportInfo = nc.mTransportInfo;
mSignalStrength = nc.mSignalStrength;
setUids(nc.mUids); // Will make the defensive copy
mEstablishingVpnAppUid = nc.mEstablishingVpnAppUid;
@@ -874,6 +877,7 @@
}
private NetworkSpecifier mNetworkSpecifier = null;
+ private TransportInfo mTransportInfo = null;
/**
* Sets the optional bearer specific network specifier.
@@ -899,6 +903,19 @@
}
/**
+ * Sets the optional transport specific information.
+ *
+ * @param transportInfo A concrete, parcelable framework class that extends
+ * {@link TransportInfo}.
+ * @return This NetworkCapabilities instance, to facilitate chaining.
+ * @hide
+ */
+ public NetworkCapabilities setTransportInfo(TransportInfo transportInfo) {
+ mTransportInfo = transportInfo;
+ return this;
+ }
+
+ /**
* Gets the optional bearer specific network specifier.
*
* @return The optional {@link NetworkSpecifier} specifying the bearer specific network
@@ -910,6 +927,19 @@
return mNetworkSpecifier;
}
+ /**
+ * Returns a transport-specific information container. The application may cast this
+ * container to a concrete sub-class based on its knowledge of the network request. The
+ * application should be able to deal with a {@code null} return value or an invalid case,
+ * e.g. use {@code instanceof} operation to verify expected type.
+ *
+ * @return A concrete implementation of the {@link TransportInfo} class or null if not
+ * available for the network.
+ */
+ @Nullable public TransportInfo getTransportInfo() {
+ return mTransportInfo;
+ }
+
private void combineSpecifiers(NetworkCapabilities nc) {
if (mNetworkSpecifier != null && !mNetworkSpecifier.equals(nc.mNetworkSpecifier)) {
throw new IllegalStateException("Can't combine two networkSpecifiers");
@@ -926,6 +956,17 @@
return Objects.equals(mNetworkSpecifier, nc.mNetworkSpecifier);
}
+ private void combineTransportInfos(NetworkCapabilities nc) {
+ if (mTransportInfo != null && !mTransportInfo.equals(nc.mTransportInfo)) {
+ throw new IllegalStateException("Can't combine two TransportInfos");
+ }
+ setTransportInfo(nc.mTransportInfo);
+ }
+
+ private boolean equalsTransportInfo(NetworkCapabilities nc) {
+ return Objects.equals(mTransportInfo, nc.mTransportInfo);
+ }
+
/**
* Magic value that indicates no signal strength provided. A request specifying this value is
* always satisfied.
@@ -1238,6 +1279,7 @@
combineTransportTypes(nc);
combineLinkBandwidths(nc);
combineSpecifiers(nc);
+ combineTransportInfos(nc);
combineSignalStrength(nc);
combineUids(nc);
combineSSIDs(nc);
@@ -1347,6 +1389,7 @@
&& equalsLinkBandwidths(that)
&& equalsSignalStrength(that)
&& equalsSpecifier(that)
+ && equalsTransportInfo(that)
&& equalsUids(that)
&& equalsSSID(that));
}
@@ -1364,7 +1407,8 @@
+ Objects.hashCode(mNetworkSpecifier) * 23
+ (mSignalStrength * 29)
+ Objects.hashCode(mUids) * 31
- + Objects.hashCode(mSSID) * 37;
+ + Objects.hashCode(mSSID) * 37
+ + Objects.hashCode(mTransportInfo) * 41;
}
@Override
@@ -1379,6 +1423,7 @@
dest.writeInt(mLinkUpBandwidthKbps);
dest.writeInt(mLinkDownBandwidthKbps);
dest.writeParcelable((Parcelable) mNetworkSpecifier, flags);
+ dest.writeParcelable((Parcelable) mTransportInfo, flags);
dest.writeInt(mSignalStrength);
dest.writeArraySet(mUids);
dest.writeString(mSSID);
@@ -1396,6 +1441,7 @@
netCap.mLinkUpBandwidthKbps = in.readInt();
netCap.mLinkDownBandwidthKbps = in.readInt();
netCap.mNetworkSpecifier = in.readParcelable(null);
+ netCap.mTransportInfo = in.readParcelable(null);
netCap.mSignalStrength = in.readInt();
netCap.mUids = (ArraySet<UidRange>) in.readArraySet(
null /* ClassLoader, null for default */);
@@ -1435,6 +1481,9 @@
if (mNetworkSpecifier != null) {
sb.append(" Specifier: <").append(mNetworkSpecifier).append(">");
}
+ if (mTransportInfo != null) {
+ sb.append(" TransportInfo: <").append(mTransportInfo).append(">");
+ }
if (hasSignalStrength()) {
sb.append(" SignalStrength: ").append(mSignalStrength);
}
@@ -1501,6 +1550,9 @@
if (mNetworkSpecifier != null) {
proto.write(NetworkCapabilitiesProto.NETWORK_SPECIFIER, mNetworkSpecifier.toString());
}
+ if (mTransportInfo != null) {
+ // TODO b/120653863: write transport-specific info to proto?
+ }
proto.write(NetworkCapabilitiesProto.CAN_REPORT_SIGNAL_STRENGTH, hasSignalStrength());
proto.write(NetworkCapabilitiesProto.SIGNAL_STRENGTH, mSignalStrength);
diff --git a/core/java/android/net/NetworkStats.java b/core/java/android/net/NetworkStats.java
index 5447f59..a00b9a3 100644
--- a/core/java/android/net/NetworkStats.java
+++ b/core/java/android/net/NetworkStats.java
@@ -44,6 +44,7 @@
*
* @hide
*/
+// @NotThreadSafe
public class NetworkStats implements Parcelable {
private static final String TAG = "NetworkStats";
/** {@link #iface} value when interface details unavailable. */
@@ -443,6 +444,26 @@
return entry;
}
+ /**
+ * If @{code dest} is not equal to @{code src}, copy entry from index @{code src} to index
+ * @{code dest}.
+ */
+ private void maybeCopyEntry(int dest, int src) {
+ if (dest == src) return;
+ iface[dest] = iface[src];
+ uid[dest] = uid[src];
+ set[dest] = set[src];
+ tag[dest] = tag[src];
+ metered[dest] = metered[src];
+ roaming[dest] = roaming[src];
+ defaultNetwork[dest] = defaultNetwork[src];
+ rxBytes[dest] = rxBytes[src];
+ rxPackets[dest] = rxPackets[src];
+ txBytes[dest] = txBytes[src];
+ txPackets[dest] = txPackets[src];
+ operations[dest] = operations[src];
+ }
+
public long getElapsedRealtime() {
return elapsedRealtime;
}
@@ -941,21 +962,18 @@
}
/**
- * Return all rows except those attributed to the requested UID; doesn't
- * mutate the original structure.
+ * Remove all rows that match one of specified UIDs.
*/
- public NetworkStats withoutUids(int[] uids) {
- final NetworkStats stats = new NetworkStats(elapsedRealtime, 10);
-
- Entry entry = new Entry();
+ public void removeUids(int[] uids) {
+ int nextOutputEntry = 0;
for (int i = 0; i < size; i++) {
- entry = getValues(i, entry);
- if (!ArrayUtils.contains(uids, entry.uid)) {
- stats.addValues(entry);
+ if (!ArrayUtils.contains(uids, uid[i])) {
+ maybeCopyEntry(nextOutputEntry, i);
+ nextOutputEntry++;
}
}
- return stats;
+ size = nextOutputEntry;
}
/**
diff --git a/core/java/android/net/PrivateDnsConnectivityChecker.java b/core/java/android/net/PrivateDnsConnectivityChecker.java
new file mode 100644
index 0000000..cfd458c
--- /dev/null
+++ b/core/java/android/net/PrivateDnsConnectivityChecker.java
@@ -0,0 +1,64 @@
+/*
+ * 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.net;
+
+import android.annotation.NonNull;
+import android.util.Log;
+
+import java.io.IOException;
+import java.net.InetSocketAddress;
+
+import javax.net.SocketFactory;
+import javax.net.ssl.SSLSocket;
+import javax.net.ssl.SSLSocketFactory;
+
+/**
+ * Class for testing connectivity to DNS-over-TLS servers.
+ * {@hide}
+ */
+public class PrivateDnsConnectivityChecker {
+ private static final String TAG = "NetworkUtils";
+
+ private static final int PRIVATE_DNS_PORT = 853;
+ private static final int CONNECTION_TIMEOUT_MS = 5000;
+
+ private PrivateDnsConnectivityChecker() { }
+
+ /**
+ * checks that a provided host can perform a TLS handshake on port 853.
+ * @param hostname host to connect to.
+ */
+ public static boolean canConnectToPrivateDnsServer(@NonNull String hostname) {
+ final SocketFactory factory = SSLSocketFactory.getDefault();
+ TrafficStats.setThreadStatsTag(TrafficStats.TAG_SYSTEM_APP);
+
+ try (SSLSocket socket = (SSLSocket) factory.createSocket()) {
+ socket.setSoTimeout(CONNECTION_TIMEOUT_MS);
+ socket.connect(new InetSocketAddress(hostname, PRIVATE_DNS_PORT));
+ if (!socket.isConnected()) {
+ Log.w(TAG, String.format("Connection to %s failed.", hostname));
+ return false;
+ }
+ socket.startHandshake();
+ Log.w(TAG, String.format("TLS handshake to %s succeeded.", hostname));
+ return true;
+ } catch (IOException e) {
+ Log.w(TAG, String.format("TLS handshake to %s failed.", hostname), e);
+ return false;
+ }
+ }
+}
diff --git a/core/java/android/net/TransportInfo.java b/core/java/android/net/TransportInfo.java
new file mode 100644
index 0000000..b78d3fe
--- /dev/null
+++ b/core/java/android/net/TransportInfo.java
@@ -0,0 +1,25 @@
+/*
+ * 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.net;
+
+/**
+ * A container for transport-specific capabilities which is returned by
+ * {@link NetworkCapabilities#getTransportInfo()}. Specific networks
+ * may provide concrete implementations of this interface.
+ */
+public interface TransportInfo {
+}
diff --git a/core/java/android/net/Uri.java b/core/java/android/net/Uri.java
index d09f33b..af3ee09 100644
--- a/core/java/android/net/Uri.java
+++ b/core/java/android/net/Uri.java
@@ -374,11 +374,12 @@
public abstract String toString();
/**
- * Return a string representation of the URI that is safe to print
- * to logs and other places where PII should be avoided.
- * @hide
+ * Return a string representation of this URI that has common forms of PII redacted,
+ * making it safer to use for logging purposes. For example, {@code tel:800-466-4411} is
+ * returned as {@code tel:xxx-xxx-xxxx} and {@code http://example.com/path/to/item/} is
+ * returned as {@code http://example.com/...}.
+ * @return the common forms PII redacted string of this URI
*/
- @UnsupportedAppUsage
public String toSafeString() {
String scheme = getScheme();
String ssp = getSchemeSpecificPart();
diff --git a/core/java/android/os/GraphicsEnvironment.java b/core/java/android/os/GraphicsEnvironment.java
index 8cafbde..7abe913 100644
--- a/core/java/android/os/GraphicsEnvironment.java
+++ b/core/java/android/os/GraphicsEnvironment.java
@@ -16,14 +16,13 @@
package android.os;
+import android.content.ContentResolver;
import android.content.Context;
import android.content.pm.ApplicationInfo;
import android.content.pm.PackageManager;
import android.content.res.AssetFileDescriptor;
import android.content.res.AssetManager;
import android.opengl.EGL14;
-import android.os.Build;
-import android.os.SystemProperties;
import android.provider.Settings;
import android.util.Log;
@@ -37,6 +36,11 @@
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
/** @hide */
public class GraphicsEnvironment {
@@ -67,7 +71,7 @@
*/
public void setup(Context context, Bundle coreSettings) {
setupGpuLayers(context, coreSettings);
- setupAngle(context, coreSettings);
+ setupAngle(context, context.getPackageName());
chooseDriver(context, coreSettings);
}
@@ -192,24 +196,101 @@
setLayerPaths(mClassLoader, layerPaths);
}
+ enum OpenGlDriverChoice {
+ DEFAULT,
+ NATIVE,
+ ANGLE
+ }
+
+ private static final Map<OpenGlDriverChoice, String> sDriverMap = buildMap();
+ private static Map<OpenGlDriverChoice, String> buildMap() {
+ Map<OpenGlDriverChoice, String> map = new HashMap<>();
+ map.put(OpenGlDriverChoice.DEFAULT, "default");
+ map.put(OpenGlDriverChoice.ANGLE, "angle");
+ map.put(OpenGlDriverChoice.NATIVE, "native");
+
+ return map;
+ }
+
+
+ private static List<String> getGlobalSettingsString(Context context, String globalSetting) {
+ List<String> valueList = null;
+ ContentResolver contentResolver = context.getContentResolver();
+ String settingsValue = Settings.Global.getString(contentResolver, globalSetting);
+
+ if (settingsValue != null) {
+ valueList = new ArrayList<>(Arrays.asList(settingsValue.split(",")));
+ } else {
+ valueList = new ArrayList<>();
+ }
+
+ return valueList;
+ }
+
+ private static int getGlobalSettingsPkgIndex(String pkgName,
+ List<String> globalSettingsDriverPkgs) {
+ for (int pkgIndex = 0; pkgIndex < globalSettingsDriverPkgs.size(); pkgIndex++) {
+ if (globalSettingsDriverPkgs.get(pkgIndex).equals(pkgName)) {
+ return pkgIndex;
+ }
+ }
+
+ return -1;
+ }
+
+ private static String getDriverForPkg(Context context, String packageName) {
+ try {
+ ContentResolver contentResolver = context.getContentResolver();
+ int allUseAngle = Settings.Global.getInt(contentResolver,
+ Settings.Global.GLOBAL_SETTINGS_ANGLE_GL_DRIVER_ALL_ANGLE);
+ if (allUseAngle == 1) {
+ return sDriverMap.get(OpenGlDriverChoice.ANGLE);
+ }
+ } catch (Settings.SettingNotFoundException e) {
+ // Do nothing and move on
+ }
+
+ List<String> globalSettingsDriverPkgs =
+ getGlobalSettingsString(context,
+ Settings.Global.GLOBAL_SETTINGS_ANGLE_GL_DRIVER_SELECTION_PKGS);
+ List<String> globalSettingsDriverValues =
+ getGlobalSettingsString(context,
+ Settings.Global.GLOBAL_SETTINGS_ANGLE_GL_DRIVER_SELECTION_VALUES);
+
+ // Make sure we have a good package name
+ if ((packageName == null) || (packageName.isEmpty())) {
+ return sDriverMap.get(OpenGlDriverChoice.DEFAULT);
+ }
+ // Make sure we have good settings to use
+ if (globalSettingsDriverPkgs.isEmpty() || globalSettingsDriverValues.isEmpty()
+ || (globalSettingsDriverPkgs.size() != globalSettingsDriverValues.size())) {
+ Log.w(TAG,
+ "Global.Settings values are invalid: "
+ + "globalSettingsDriverPkgs.size = "
+ + globalSettingsDriverPkgs.size() + ", "
+ + "globalSettingsDriverValues.size = "
+ + globalSettingsDriverValues.size());
+ return sDriverMap.get(OpenGlDriverChoice.DEFAULT);
+ }
+
+ int pkgIndex = getGlobalSettingsPkgIndex(packageName, globalSettingsDriverPkgs);
+
+ if (pkgIndex < 0) {
+ return sDriverMap.get(OpenGlDriverChoice.DEFAULT);
+ }
+
+ return globalSettingsDriverValues.get(pkgIndex);
+ }
+
/**
* Pass ANGLE details down to trigger enable logic
*/
- private static void setupAngle(Context context, Bundle coreSettings) {
+ private void setupAngle(Context context, String packageName) {
+ String devOptIn = getDriverForPkg(context, packageName);
- String angleEnabledApp =
- coreSettings.getString(Settings.Global.ANGLE_ENABLED_APP);
-
- String packageName = context.getPackageName();
-
- boolean devOptIn = false;
- if ((angleEnabledApp != null && packageName != null)
- && (!angleEnabledApp.isEmpty() && !packageName.isEmpty())
- && angleEnabledApp.equals(packageName)) {
-
- Log.i(TAG, packageName + " opted in for ANGLE via Developer Setting");
-
- devOptIn = true;
+ if (DEBUG) {
+ Log.v(TAG, "ANGLE Developer option for '" + packageName + "' "
+ + "set to: '" + devOptIn + "'");
}
ApplicationInfo angleInfo;
@@ -303,8 +384,7 @@
// Further opt-in logic is handled in native, so pass relevant info down
// TODO: Move the ANGLE selection logic earlier so we don't need to keep these
// file descriptors open.
- setAngleInfo(paths, packageName, devOptIn,
- rulesFd, rulesOffset, rulesLength);
+ setAngleInfo(paths, packageName, devOptIn, rulesFd, rulesOffset, rulesLength);
}
/**
@@ -452,6 +532,6 @@
private static native void setDebugLayersGLES(String layers);
private static native void setDriverPath(String path);
private static native void setAngleInfo(String path, String appPackage,
- boolean devOptIn, FileDescriptor rulesFd,
+ String devOptIn, FileDescriptor rulesFd,
long rulesOffset, long rulesLength);
}
diff --git a/core/java/android/os/UserManager.java b/core/java/android/os/UserManager.java
index 86f81d8..17ce79b 100644
--- a/core/java/android/os/UserManager.java
+++ b/core/java/android/os/UserManager.java
@@ -1225,6 +1225,9 @@
* system user hasn't been unlocked yet, or {@link #DISALLOW_USER_SWITCH} is set.
* @hide
*/
+ @SystemApi
+ @RequiresPermission(anyOf = {android.Manifest.permission.MANAGE_USERS,
+ android.Manifest.permission.INTERACT_ACROSS_USERS}, conditional = true)
public boolean canSwitchUsers() {
boolean allowUserSwitchingWhenSystemUserLocked = Settings.Global.getInt(
mContext.getContentResolver(),
@@ -2646,6 +2649,19 @@
}
/**
+ * Removes a user and all associated data.
+ *
+ * @param user the user that needs to be removed.
+ * @hide
+ */
+ @SystemApi
+ @RequiresPermission(android.Manifest.permission.MANAGE_USERS)
+ public boolean removeUser(UserHandle user) {
+ return removeUser(user.getIdentifier());
+ }
+
+
+ /**
* Similar to {@link #removeUser(int)} except bypassing the checking of
* {@link UserManager#DISALLOW_REMOVE_USER}
* or {@link UserManager#DISALLOW_REMOVE_MANAGED_PROFILE}.
diff --git a/core/java/android/permission/IRuntimePermissionPresenter.aidl b/core/java/android/permission/IRuntimePermissionPresenter.aidl
new file mode 100644
index 0000000..693d21b
--- /dev/null
+++ b/core/java/android/permission/IRuntimePermissionPresenter.aidl
@@ -0,0 +1,29 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.permission;
+
+import android.os.RemoteCallback;
+
+/**
+ * Interface for communication with the permission presenter service.
+ *
+ * @hide
+ */
+oneway interface IRuntimePermissionPresenter {
+ void getAppPermissions(String packageName, in RemoteCallback callback);
+ void revokeRuntimePermission(String packageName, String permissionName);
+}
diff --git a/core/java/android/content/pm/permission/RuntimePermissionPresentationInfo.aidl b/core/java/android/permission/RuntimePermissionPresentationInfo.aidl
similarity index 94%
rename from core/java/android/content/pm/permission/RuntimePermissionPresentationInfo.aidl
rename to core/java/android/permission/RuntimePermissionPresentationInfo.aidl
index f96a32f..533c1ff 100644
--- a/core/java/android/content/pm/permission/RuntimePermissionPresentationInfo.aidl
+++ b/core/java/android/permission/RuntimePermissionPresentationInfo.aidl
@@ -14,6 +14,6 @@
* limitations under the License.
*/
-package android.content.pm.permission;
+package android.permission;
parcelable RuntimePermissionPresentationInfo;
diff --git a/core/java/android/permission/RuntimePermissionPresentationInfo.java b/core/java/android/permission/RuntimePermissionPresentationInfo.java
new file mode 100644
index 0000000..ed7b05c
--- /dev/null
+++ b/core/java/android/permission/RuntimePermissionPresentationInfo.java
@@ -0,0 +1,110 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.permission;
+
+import android.annotation.NonNull;
+import android.annotation.SystemApi;
+import android.os.Parcel;
+import android.os.Parcelable;
+
+/**
+ * This class contains information about how a runtime permission
+ * is to be presented in the UI. A single runtime permission
+ * presented to the user may correspond to multiple platform defined
+ * permissions, e.g. the location permission may control both the
+ * coarse and fine platform permissions.
+ *
+ * @hide
+ */
+@SystemApi
+public final class RuntimePermissionPresentationInfo implements Parcelable {
+ private static final int FLAG_GRANTED = 1 << 0;
+ private static final int FLAG_STANDARD = 1 << 1;
+
+ private final CharSequence mLabel;
+ private final int mFlags;
+
+ /**
+ * Creates a new instance.
+ *
+ * @param label The permission label.
+ * @param granted Whether the permission is granted.
+ * @param standard Whether this is a platform-defined permission.
+ */
+ public RuntimePermissionPresentationInfo(CharSequence label,
+ boolean granted, boolean standard) {
+ mLabel = label;
+ int flags = 0;
+ if (granted) {
+ flags |= FLAG_GRANTED;
+ }
+ if (standard) {
+ flags |= FLAG_STANDARD;
+ }
+ mFlags = flags;
+ }
+
+ private RuntimePermissionPresentationInfo(Parcel parcel) {
+ mLabel = parcel.readCharSequence();
+ mFlags = parcel.readInt();
+ }
+
+ /**
+ * @return Whether the permission is granted.
+ */
+ public boolean isGranted() {
+ return (mFlags & FLAG_GRANTED) != 0;
+ }
+
+ /**
+ * @return Whether the permission is platform-defined.
+ */
+ public boolean isStandard() {
+ return (mFlags & FLAG_STANDARD) != 0;
+ }
+
+ /**
+ * Gets the permission label.
+ *
+ * @return The label.
+ */
+ public @NonNull CharSequence getLabel() {
+ return mLabel;
+ }
+
+ @Override
+ public int describeContents() {
+ return 0;
+ }
+
+ @Override
+ public void writeToParcel(Parcel parcel, int flags) {
+ parcel.writeCharSequence(mLabel);
+ parcel.writeInt(mFlags);
+ }
+
+ public static final Creator<RuntimePermissionPresentationInfo> CREATOR =
+ new Creator<RuntimePermissionPresentationInfo>() {
+ public RuntimePermissionPresentationInfo createFromParcel(Parcel source) {
+ return new RuntimePermissionPresentationInfo(source);
+ }
+
+ public RuntimePermissionPresentationInfo[] newArray(int size) {
+ return new RuntimePermissionPresentationInfo[size];
+ }
+ };
+}
diff --git a/core/java/android/content/pm/permission/RuntimePermissionPresenter.java b/core/java/android/permission/RuntimePermissionPresenter.java
similarity index 94%
rename from core/java/android/content/pm/permission/RuntimePermissionPresenter.java
rename to core/java/android/permission/RuntimePermissionPresenter.java
index 73addb7..ed9165e 100644
--- a/core/java/android/content/pm/permission/RuntimePermissionPresenter.java
+++ b/core/java/android/permission/RuntimePermissionPresenter.java
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-package android.content.pm.permission;
+package android.permission;
import static com.android.internal.util.Preconditions.checkNotNull;
import static com.android.internal.util.function.pooled.PooledLambda.obtainMessage;
@@ -30,7 +30,6 @@
import android.os.Message;
import android.os.RemoteCallback;
import android.os.RemoteException;
-import android.permissionpresenterservice.RuntimePermissionPresenterService;
import android.util.Log;
import com.android.internal.annotations.GuardedBy;
@@ -60,20 +59,17 @@
* @hide
*/
public static final String KEY_RESULT =
- "android.content.pm.permission.RuntimePermissionPresenter.key.result";
+ "android.permission.RuntimePermissionPresenter.key.result";
/**
* Listener for delivering a result.
*/
- public static abstract class OnResultCallback {
+ public interface OnResultCallback {
/**
* The result for {@link #getAppPermissions(String, OnResultCallback, Handler)}.
* @param permissions The permissions list.
*/
- public void onGetAppPermissions(@NonNull
- List<RuntimePermissionPresentationInfo> permissions) {
- /* do nothing - stub */
- }
+ void onGetAppPermissions(@NonNull List<RuntimePermissionPresentationInfo> permissions);
}
private static final Object sLock = new Object();
@@ -152,7 +148,7 @@
@GuardedBy("mLock")
private boolean mBound;
- public RemoteService(Context context) {
+ RemoteService(Context context) {
super(context.getMainLooper(), null, false);
mContext = context;
}
diff --git a/core/java/android/permission/RuntimePermissionPresenterService.java b/core/java/android/permission/RuntimePermissionPresenterService.java
new file mode 100644
index 0000000..e50fc5a
--- /dev/null
+++ b/core/java/android/permission/RuntimePermissionPresenterService.java
@@ -0,0 +1,122 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.permission;
+
+import static com.android.internal.util.Preconditions.checkNotNull;
+import static com.android.internal.util.function.pooled.PooledLambda.obtainMessage;
+
+import android.annotation.NonNull;
+import android.annotation.SystemApi;
+import android.app.Service;
+import android.content.Context;
+import android.content.Intent;
+import android.os.Bundle;
+import android.os.Handler;
+import android.os.IBinder;
+import android.os.RemoteCallback;
+
+import java.util.List;
+
+/**
+ * This service presents information regarding runtime permissions that is
+ * used for presenting them in the UI. Runtime permissions are presented as
+ * a single permission in the UI but may be composed of several individual
+ * permissions.
+ *
+ * @see RuntimePermissionPresenter
+ * @see RuntimePermissionPresentationInfo
+ *
+ * @hide
+ */
+@SystemApi
+public abstract class RuntimePermissionPresenterService extends Service {
+
+ /**
+ * The {@link Intent} action that must be declared as handled by a service
+ * in its manifest for the system to recognize it as a runtime permission
+ * presenter service.
+ */
+ public static final String SERVICE_INTERFACE =
+ "android.permission.RuntimePermissionPresenterService";
+
+ // No need for locking - always set first and never modified
+ private Handler mHandler;
+
+ @Override
+ public final void attachBaseContext(Context base) {
+ super.attachBaseContext(base);
+ mHandler = new Handler(base.getMainLooper());
+ }
+
+ /**
+ * Gets the runtime permissions for an app.
+ *
+ * @param packageName The package for which to query.
+ *
+ * @return descriptions of the runtime permissions of the app
+ */
+ public abstract @NonNull List<RuntimePermissionPresentationInfo> onGetAppPermissions(
+ @NonNull String packageName);
+
+ /**
+ * Revokes the permission {@code permissionName} for app {@code packageName}
+ *
+ * @param packageName The package for which to revoke
+ * @param permissionName The permission to revoke
+ */
+ public abstract void onRevokeRuntimePermission(@NonNull String packageName,
+ @NonNull String permissionName);
+
+ @Override
+ public final IBinder onBind(Intent intent) {
+ return new IRuntimePermissionPresenter.Stub() {
+ @Override
+ public void getAppPermissions(String packageName, RemoteCallback callback) {
+ checkNotNull(packageName, "packageName");
+ checkNotNull(callback, "callback");
+
+ mHandler.sendMessage(
+ obtainMessage(
+ RuntimePermissionPresenterService::getAppPermissions,
+ RuntimePermissionPresenterService.this, packageName, callback));
+ }
+
+ @Override
+ public void revokeRuntimePermission(String packageName, String permissionName) {
+ checkNotNull(packageName, "packageName");
+ checkNotNull(permissionName, "permissionName");
+
+ mHandler.sendMessage(
+ obtainMessage(
+ RuntimePermissionPresenterService::onRevokeRuntimePermission,
+ RuntimePermissionPresenterService.this, packageName,
+ permissionName));
+ }
+ };
+ }
+
+ private void getAppPermissions(@NonNull String packageName, @NonNull RemoteCallback callback) {
+ List<RuntimePermissionPresentationInfo> permissions = onGetAppPermissions(packageName);
+ if (permissions != null && !permissions.isEmpty()) {
+ Bundle result = new Bundle();
+ result.putParcelableList(RuntimePermissionPresenter.KEY_RESULT, permissions);
+ callback.sendResult(result);
+ } else {
+ callback.sendResult(null);
+ }
+ }
+}
diff --git a/core/java/android/permissionpresenterservice/RuntimePermissionPresenterService.java b/core/java/android/permissionpresenterservice/RuntimePermissionPresenterService.java
index a41a644..2b3f0f5 100644
--- a/core/java/android/permissionpresenterservice/RuntimePermissionPresenterService.java
+++ b/core/java/android/permissionpresenterservice/RuntimePermissionPresenterService.java
@@ -26,7 +26,6 @@
import android.content.Intent;
import android.content.pm.permission.IRuntimePermissionPresenter;
import android.content.pm.permission.RuntimePermissionPresentationInfo;
-import android.content.pm.permission.RuntimePermissionPresenter;
import android.os.Bundle;
import android.os.Handler;
import android.os.IBinder;
@@ -40,11 +39,13 @@
* a single permission in the UI but may be composed of several individual
* permissions.
*
- * @see RuntimePermissionPresenter
* @see RuntimePermissionPresentationInfo
*
* @hide
+ *
+ * @deprecated use {@link android.permission.RuntimePermissionPresenterService} instead
*/
+@Deprecated
@SystemApi
public abstract class RuntimePermissionPresenterService extends Service {
@@ -56,6 +57,9 @@
public static final String SERVICE_INTERFACE =
"android.permissionpresenterservice.RuntimePermissionPresenterService";
+ private static final String KEY_RESULT =
+ "android.content.pm.permission.RuntimePermissionPresenter.key.result";
+
// No need for locking - always set first and never modified
private Handler mHandler;
@@ -112,7 +116,7 @@
List<RuntimePermissionPresentationInfo> permissions = onGetAppPermissions(packageName);
if (permissions != null && !permissions.isEmpty()) {
Bundle result = new Bundle();
- result.putParcelableList(RuntimePermissionPresenter.KEY_RESULT, permissions);
+ result.putParcelableList(KEY_RESULT, permissions);
callback.sendResult(result);
} else {
callback.sendResult(null);
diff --git a/core/java/android/provider/CalendarContract.java b/core/java/android/provider/CalendarContract.java
index a8f3665..865b8f8 100644
--- a/core/java/android/provider/CalendarContract.java
+++ b/core/java/android/provider/CalendarContract.java
@@ -16,13 +16,14 @@
package android.provider;
-
import android.annotation.SdkConstant;
import android.annotation.SdkConstant.SdkConstantType;
import android.annotation.UnsupportedAppUsage;
import android.app.Activity;
import android.app.AlarmManager;
import android.app.PendingIntent;
+import android.app.admin.DevicePolicyManager;
+import android.content.ComponentName;
import android.content.ContentProviderClient;
import android.content.ContentResolver;
import android.content.ContentUris;
@@ -694,6 +695,37 @@
public static final Uri CONTENT_URI = Uri.parse("content://" + AUTHORITY + "/calendars");
/**
+ * The content:// style URL for querying Calendars table in the work profile. Appending a
+ * calendar id using {@link ContentUris#withAppendedId(Uri, long)} will
+ * specify a single calendar.
+ *
+ * <p>The following columns are allowed to be queried via this uri:
+ * <ul>
+ * <li>{@link #_ID}</li>
+ * <li>{@link #NAME}</li>
+ * <li>{@link #CALENDAR_DISPLAY_NAME}</li>
+ * <li>{@link #CALENDAR_COLOR}</li>
+ * <li>{@link #VISIBLE}</li>
+ * <li>{@link #CALENDAR_LOCATION}</li>
+ * <li>{@link #CALENDAR_TIME_ZONE}</li>
+ * <li>{@link #IS_PRIMARY}</li>
+ * </ul>
+ *
+ * <p>{@link IllegalArgumentException} will be thrown if there exist columns in the
+ * projection of the query to this uri that are not contained in the above list.
+ *
+ * <p>This uri will return an empty cursor if the calling user is not a parent profile
+ * of a work profile, or cross profile calendar is disabled in Settings, or this uri is
+ * queried from a package that is not whitelisted by profile owner of the work profile via
+ * {@link DevicePolicyManager#addCrossProfileCalendarPackage(ComponentName, String)}.
+ *
+ * @see DevicePolicyManager#getCrossProfileCalendarPackages(ComponentName)
+ * @see Settings.Secure#CROSS_PROFILE_CALENDAR_ENABLED
+ */
+ public static final Uri ENTERPRISE_CONTENT_URI =
+ Uri.parse("content://" + AUTHORITY + "/enterprise/calendars");
+
+ /**
* The default sort order for this table
*/
public static final String DEFAULT_SORT_ORDER = CALENDAR_DISPLAY_NAME;
@@ -1641,6 +1673,50 @@
Uri.parse("content://" + AUTHORITY + "/events");
/**
+ * The content:// style URL for querying Events table in the work profile. Appending an
+ * event id using {@link ContentUris#withAppendedId(Uri, long)} will
+ * specify a single event.
+ *
+ * <p>The following columns are allowed to be queried via this uri:
+ * <ul>
+ * <li>{@link #_ID}</li>
+ * <li>{@link #CALENDAR_ID}</li>
+ * <li>{@link #TITLE}</li>
+ * <li>{@link #EVENT_LOCATION}</li>
+ * <li>{@link #EVENT_COLOR}</li>
+ * <li>{@link #STATUS}</li>
+ * <li>{@link #DTSTART}</li>
+ * <li>{@link #DTEND}</li>
+ * <li>{@link #EVENT_TIMEZONE}</li>
+ * <li>{@link #EVENT_END_TIMEZONE}</li>
+ * <li>{@link #DURATION}</li>
+ * <li>{@link #ALL_DAY}</li>
+ * <li>{@link #AVAILABILITY}</li>
+ * <li>{@link #RRULE}</li>
+ * <li>{@link #RDATE}</li>
+ * <li>{@link #EXRULE}</li>
+ * <li>{@link #EXDATE}</li>
+ * <li>{@link #CALENDAR_DISPLAY_NAME}</li>
+ * <li>{@link #CALENDAR_COLOR}</li>
+ * <li>{@link #VISIBLE}</li>
+ * <li>{@link #CALENDAR_TIME_ZONE}</li>
+ * </ul>
+ *
+ * <p>{@link IllegalArgumentException} will be thrown if there exist columns in the
+ * projection of the query to this uri that are not contained in the above list.
+ *
+ * <p>This uri will return an empty cursor if the calling user is not a parent profile
+ * of a work profile, or cross profile calendar is disabled in Settings, or this uri is
+ * queried from a package that is not whitelisted by profile owner of the work profile via
+ * {@link DevicePolicyManager#addCrossProfileCalendarPackage(ComponentName, String)}.
+ *
+ * @see DevicePolicyManager#getCrossProfileCalendarPackages(ComponentName)
+ * @see Settings.Secure#CROSS_PROFILE_CALENDAR_ENABLED
+ */
+ public static final Uri ENTERPRISE_CONTENT_URI =
+ Uri.parse("content://" + AUTHORITY + "/enterprise/events");
+
+ /**
* The content:// style URI for recurring event exceptions. Insertions require an
* appended event ID. Deletion of exceptions requires both the original event ID and
* the exception event ID (see {@link Uri.Builder#appendPath}).
@@ -1820,6 +1896,63 @@
Uri.parse("content://" + AUTHORITY + "/instances/searchbyday");
/**
+ * The content:// style URL for querying an instance range in the work profile.
+ * It supports similar semantics as {@link #CONTENT_URI}.
+ *
+ * <p>The following columns plus the columns that are whitelisted by
+ * {@link Events#ENTERPRISE_CONTENT_URI} are allowed to be queried via this uri:
+ * <ul>
+ * <li>{@link #_ID}</li>
+ * <li>{@link #EVENT_ID}</li>
+ * <li>{@link #BEGIN}</li>
+ * <li>{@link #END}</li>
+ * <li>{@link #START_DAY}</li>
+ * <li>{@link #END_DAY}</li>
+ * <li>{@link #START_MINUTE}</li>
+ * <li>{@link #END_MINUTE}</li>
+ * </ul>
+ *
+ * <p>{@link IllegalArgumentException} will be thrown if there exist columns in the
+ * projection of the query to this uri that are not contained in the above list.
+ *
+ * <p>This uri will return an empty cursor if the calling user is not a parent profile
+ * of a work profile, or cross profile calendar for the work profile is disabled in
+ * Settings, or this uri is queried from a package that is not whitelisted by
+ * profile owner of the work profile via
+ * {@link DevicePolicyManager#addCrossProfileCalendarPackage(ComponentName, String)}.
+ *
+ * @see DevicePolicyManager#getCrossProfileCalendarPackages(ComponentName)
+ * @see Settings.Secure#CROSS_PROFILE_CALENDAR_ENABLED
+ */
+ public static final Uri ENTERPRISE_CONTENT_URI =
+ Uri.parse("content://" + AUTHORITY + "/enterprise/instances/when");
+
+ /**
+ * The content:// style URL for querying an instance range by Julian
+ * Day in the work profile. It supports similar semantics as {@link #CONTENT_BY_DAY_URI}
+ * and performs similar checks as {@link #ENTERPRISE_CONTENT_URI}.
+ */
+ public static final Uri ENTERPRISE_CONTENT_BY_DAY_URI =
+ Uri.parse("content://" + AUTHORITY + "/enterprise/instances/whenbyday");
+
+ /**
+ * The content:// style URL for querying an instance range with a search
+ * term in the work profile. It supports similar semantics as {@link #CONTENT_SEARCH_URI}
+ * and performs similar checks as {@link #ENTERPRISE_CONTENT_URI}.
+ */
+ public static final Uri ENTERPRISE_CONTENT_SEARCH_URI =
+ Uri.parse("content://" + AUTHORITY + "/enterprise/instances/search");
+
+ /**
+ * The content:// style URL for querying an instance range with a search
+ * term in the work profile. It supports similar semantics as
+ * {@link #CONTENT_SEARCH_BY_DAY_URI} and performs similar checks as
+ * {@link #ENTERPRISE_CONTENT_URI}.
+ */
+ public static final Uri ENTERPRISE_CONTENT_SEARCH_BY_DAY_URI =
+ Uri.parse("content://" + AUTHORITY + "/enterprise/instances/searchbyday");
+
+ /**
* The default sort order for this table.
*/
private static final String DEFAULT_SORT_ORDER = "begin ASC";
diff --git a/core/java/android/provider/DocumentsContract.java b/core/java/android/provider/DocumentsContract.java
index 4737577..ff77228 100644
--- a/core/java/android/provider/DocumentsContract.java
+++ b/core/java/android/provider/DocumentsContract.java
@@ -24,7 +24,7 @@
import android.annotation.Nullable;
import android.annotation.SystemApi;
import android.annotation.UnsupportedAppUsage;
-import android.content.ContentProviderClient;
+import android.content.ContentInterface;
import android.content.ContentResolver;
import android.content.Context;
import android.content.Intent;
@@ -48,10 +48,10 @@
import android.os.Parcelable;
import android.os.ParcelableException;
import android.os.RemoteException;
-import android.os.storage.StorageVolume;
-import android.util.DataUnit;
import android.util.Log;
+import dalvik.system.VMRuntime;
+
import java.io.File;
import java.io.FileNotFoundException;
import java.io.IOException;
@@ -68,8 +68,7 @@
* All client apps must hold a valid URI permission grant to access documents,
* typically issued when a user makes a selection through
* {@link Intent#ACTION_OPEN_DOCUMENT}, {@link Intent#ACTION_CREATE_DOCUMENT},
- * {@link Intent#ACTION_OPEN_DOCUMENT_TREE}, or
- * {@link StorageVolume#createAccessIntent(String) StorageVolume.createAccessIntent}.
+ * or {@link Intent#ACTION_OPEN_DOCUMENT_TREE}.
*
* @see DocumentsProvider
*/
@@ -234,11 +233,6 @@
public static final String
ACTION_DOCUMENT_ROOT_SETTINGS = "android.provider.action.DOCUMENT_ROOT_SETTINGS";
- /**
- * Buffer is large enough to rewind past any EXIF headers.
- */
- private static final int THUMBNAIL_BUFFER_SIZE = (int) DataUnit.KIBIBYTES.toBytes(128);
-
/** {@hide} */
public static final String EXTERNAL_STORAGE_PROVIDER_AUTHORITY =
"com.android.externalstorage.documents";
@@ -381,7 +375,7 @@
* Flag indicating that a document can be represented as a thumbnail.
*
* @see #COLUMN_FLAGS
- * @see DocumentsContract#getDocumentThumbnail(ContentResolver, Uri,
+ * @see DocumentsContract#getDocumentThumbnail(ContentInterface, Uri,
* Point, CancellationSignal)
* @see DocumentsProvider#openDocumentThumbnail(String, Point,
* android.os.CancellationSignal)
@@ -407,7 +401,7 @@
* Flag indicating that a document is deletable.
*
* @see #COLUMN_FLAGS
- * @see DocumentsContract#deleteDocument(ContentResolver, Uri)
+ * @see DocumentsContract#deleteDocument(ContentInterface, Uri)
* @see DocumentsProvider#deleteDocument(String)
*/
public static final int FLAG_SUPPORTS_DELETE = 1 << 2;
@@ -445,8 +439,7 @@
* Flag indicating that a document can be renamed.
*
* @see #COLUMN_FLAGS
- * @see DocumentsContract#renameDocument(ContentResolver, Uri,
- * String)
+ * @see DocumentsContract#renameDocument(ContentInterface, Uri, String)
* @see DocumentsProvider#renameDocument(String, String)
*/
public static final int FLAG_SUPPORTS_RENAME = 1 << 6;
@@ -456,7 +449,7 @@
* within the same document provider.
*
* @see #COLUMN_FLAGS
- * @see DocumentsContract#copyDocument(ContentResolver, Uri, Uri)
+ * @see DocumentsContract#copyDocument(ContentInterface, Uri, Uri)
* @see DocumentsProvider#copyDocument(String, String)
*/
public static final int FLAG_SUPPORTS_COPY = 1 << 7;
@@ -466,7 +459,7 @@
* within the same document provider.
*
* @see #COLUMN_FLAGS
- * @see DocumentsContract#moveDocument(ContentResolver, Uri, Uri, Uri)
+ * @see DocumentsContract#moveDocument(ContentInterface, Uri, Uri, Uri)
* @see DocumentsProvider#moveDocument(String, String, String)
*/
public static final int FLAG_SUPPORTS_MOVE = 1 << 8;
@@ -490,7 +483,7 @@
* Flag indicating that a document can be removed from a parent.
*
* @see #COLUMN_FLAGS
- * @see DocumentsContract#removeDocument(ContentResolver, Uri, Uri)
+ * @see DocumentsContract#removeDocument(ContentInterface, Uri, Uri)
* @see DocumentsProvider#removeDocument(String, String)
*/
public static final int FLAG_SUPPORTS_REMOVE = 1 << 10;
@@ -684,7 +677,7 @@
* Flag indicating that this root can be ejected.
*
* @see #COLUMN_FLAGS
- * @see DocumentsContract#ejectRoot(ContentResolver, Uri)
+ * @see DocumentsContract#ejectRoot(ContentInterface, Uri)
* @see DocumentsProvider#ejectRoot(String)
*/
public static final int FLAG_SUPPORTS_EJECT = 1 << 5;
@@ -807,10 +800,7 @@
/** {@hide} */
public static final String EXTRA_URI_PERMISSIONS = "uriPermissions";
- /**
- * @see #createWebLinkIntent(ContentResolver, Uri, Bundle)
- * {@hide}
- */
+ /** {@hide} */
public static final String EXTRA_OPTIONS = "options";
private static final String PATH_ROOT = "root";
@@ -1255,32 +1245,20 @@
* @see DocumentsProvider#openDocumentThumbnail(String, Point,
* android.os.CancellationSignal)
*/
- public static Bitmap getDocumentThumbnail(
- ContentResolver resolver, Uri documentUri, Point size, CancellationSignal signal)
- throws FileNotFoundException {
- final ContentProviderClient client = resolver.acquireUnstableContentProviderClient(
- documentUri.getAuthority());
+ public static Bitmap getDocumentThumbnail(ContentInterface content, Uri documentUri, Point size,
+ CancellationSignal signal) throws FileNotFoundException {
try {
- return getDocumentThumbnail(client, documentUri, size, signal);
+ return ContentResolver.loadThumbnail(content, documentUri, Point.convert(size), signal,
+ ImageDecoder.ALLOCATOR_SOFTWARE);
} catch (Exception e) {
if (!(e instanceof OperationCanceledException)) {
Log.w(TAG, "Failed to load thumbnail for " + documentUri + ": " + e);
}
- rethrowIfNecessary(resolver, e);
+ rethrowIfNecessary(e);
return null;
- } finally {
- ContentProviderClient.releaseQuietly(client);
}
}
- /** {@hide} */
- @UnsupportedAppUsage
- public static Bitmap getDocumentThumbnail(ContentProviderClient client, Uri documentUri,
- Point size, CancellationSignal signal) throws IOException {
- return ContentResolver.loadThumbnail(client, documentUri, Point.convert(size), signal,
- ImageDecoder.ALLOCATOR_SOFTWARE);
- }
-
/**
* Create a new document with given MIME type and display name.
*
@@ -1289,33 +1267,24 @@
* @param displayName name of new document
* @return newly created document, or {@code null} if failed
*/
- public static Uri createDocument(ContentResolver resolver, Uri parentDocumentUri,
+ public static Uri createDocument(ContentInterface content, Uri parentDocumentUri,
String mimeType, String displayName) throws FileNotFoundException {
- final ContentProviderClient client = resolver.acquireUnstableContentProviderClient(
- parentDocumentUri.getAuthority());
try {
- return createDocument(client, parentDocumentUri, mimeType, displayName);
+ final Bundle in = new Bundle();
+ in.putParcelable(DocumentsContract.EXTRA_URI, parentDocumentUri);
+ in.putString(Document.COLUMN_MIME_TYPE, mimeType);
+ in.putString(Document.COLUMN_DISPLAY_NAME, displayName);
+
+ final Bundle out = content.call(parentDocumentUri.getAuthority(),
+ METHOD_CREATE_DOCUMENT, null, in);
+ return out.getParcelable(DocumentsContract.EXTRA_URI);
} catch (Exception e) {
Log.w(TAG, "Failed to create document", e);
- rethrowIfNecessary(resolver, e);
+ rethrowIfNecessary(e);
return null;
- } finally {
- ContentProviderClient.releaseQuietly(client);
}
}
- /** {@hide} */
- public static Uri createDocument(ContentProviderClient client, Uri parentDocumentUri,
- String mimeType, String displayName) throws RemoteException {
- final Bundle in = new Bundle();
- in.putParcelable(DocumentsContract.EXTRA_URI, parentDocumentUri);
- in.putString(Document.COLUMN_MIME_TYPE, mimeType);
- in.putString(Document.COLUMN_DISPLAY_NAME, displayName);
-
- final Bundle out = client.call(METHOD_CREATE_DOCUMENT, null, in);
- return out.getParcelable(DocumentsContract.EXTRA_URI);
- }
-
/**
* Test if a document is descendant (child, grandchild, etc) from the given
@@ -1326,39 +1295,29 @@
* @return if given document is a descendant of the given parent.
* @see Root#FLAG_SUPPORTS_IS_CHILD
*/
- public static boolean isChildDocument(ContentResolver resolver, Uri parentDocumentUri,
+ public static boolean isChildDocument(ContentInterface content, Uri parentDocumentUri,
Uri childDocumentUri) throws FileNotFoundException {
- final ContentProviderClient client = resolver.acquireUnstableContentProviderClient(
- parentDocumentUri.getAuthority());
try {
- return isChildDocument(client, parentDocumentUri, childDocumentUri);
+ final Bundle in = new Bundle();
+ in.putParcelable(DocumentsContract.EXTRA_URI, parentDocumentUri);
+ in.putParcelable(DocumentsContract.EXTRA_TARGET_URI, childDocumentUri);
+
+ final Bundle out = content.call(parentDocumentUri.getAuthority(),
+ METHOD_IS_CHILD_DOCUMENT, null, in);
+ if (out == null) {
+ throw new RemoteException("Failed to get a reponse from isChildDocument query.");
+ }
+ if (!out.containsKey(DocumentsContract.EXTRA_RESULT)) {
+ throw new RemoteException("Response did not include result field..");
+ }
+ return out.getBoolean(DocumentsContract.EXTRA_RESULT);
} catch (Exception e) {
- Log.w(TAG, "Failed to query isChildDocument", e);
- rethrowIfNecessary(resolver, e);
+ Log.w(TAG, "Failed to create document", e);
+ rethrowIfNecessary(e);
return false;
- } finally {
- ContentProviderClient.releaseQuietly(client);
}
}
- /** {@hide} */
- public static boolean isChildDocument(ContentProviderClient client, Uri parentDocumentUri,
- Uri childDocumentUri) throws RemoteException {
-
- final Bundle in = new Bundle();
- in.putParcelable(DocumentsContract.EXTRA_URI, parentDocumentUri);
- in.putParcelable(DocumentsContract.EXTRA_TARGET_URI, childDocumentUri);
-
- final Bundle out = client.call(METHOD_IS_CHILD_DOCUMENT, null, in);
- if (out == null) {
- throw new RemoteException("Failed to get a response from isChildDocument query.");
- }
- if (!out.containsKey(DocumentsContract.EXTRA_RESULT)) {
- throw new RemoteException("Response did not include result field..");
- }
- return out.getBoolean(DocumentsContract.EXTRA_RESULT);
- }
-
/**
* Change the display name of an existing document.
* <p>
@@ -1372,64 +1331,46 @@
* @return the existing or new document after the rename, or {@code null} if
* failed.
*/
- public static Uri renameDocument(ContentResolver resolver, Uri documentUri,
+ public static Uri renameDocument(ContentInterface content, Uri documentUri,
String displayName) throws FileNotFoundException {
- final ContentProviderClient client = resolver.acquireUnstableContentProviderClient(
- documentUri.getAuthority());
try {
- return renameDocument(client, documentUri, displayName);
+ final Bundle in = new Bundle();
+ in.putParcelable(DocumentsContract.EXTRA_URI, documentUri);
+ in.putString(Document.COLUMN_DISPLAY_NAME, displayName);
+
+ final Bundle out = content.call(documentUri.getAuthority(),
+ METHOD_RENAME_DOCUMENT, null, in);
+ final Uri outUri = out.getParcelable(DocumentsContract.EXTRA_URI);
+ return (outUri != null) ? outUri : documentUri;
} catch (Exception e) {
Log.w(TAG, "Failed to rename document", e);
- rethrowIfNecessary(resolver, e);
+ rethrowIfNecessary(e);
return null;
- } finally {
- ContentProviderClient.releaseQuietly(client);
}
}
- /** {@hide} */
- public static Uri renameDocument(ContentProviderClient client, Uri documentUri,
- String displayName) throws RemoteException {
- final Bundle in = new Bundle();
- in.putParcelable(DocumentsContract.EXTRA_URI, documentUri);
- in.putString(Document.COLUMN_DISPLAY_NAME, displayName);
-
- final Bundle out = client.call(METHOD_RENAME_DOCUMENT, null, in);
- final Uri outUri = out.getParcelable(DocumentsContract.EXTRA_URI);
- return (outUri != null) ? outUri : documentUri;
- }
-
/**
* Delete the given document.
*
* @param documentUri document with {@link Document#FLAG_SUPPORTS_DELETE}
* @return if the document was deleted successfully.
*/
- public static boolean deleteDocument(ContentResolver resolver, Uri documentUri)
+ public static boolean deleteDocument(ContentInterface content, Uri documentUri)
throws FileNotFoundException {
- final ContentProviderClient client = resolver.acquireUnstableContentProviderClient(
- documentUri.getAuthority());
try {
- deleteDocument(client, documentUri);
+ final Bundle in = new Bundle();
+ in.putParcelable(DocumentsContract.EXTRA_URI, documentUri);
+
+ content.call(documentUri.getAuthority(),
+ METHOD_DELETE_DOCUMENT, null, in);
return true;
} catch (Exception e) {
Log.w(TAG, "Failed to delete document", e);
- rethrowIfNecessary(resolver, e);
+ rethrowIfNecessary(e);
return false;
- } finally {
- ContentProviderClient.releaseQuietly(client);
}
}
- /** {@hide} */
- public static void deleteDocument(ContentProviderClient client, Uri documentUri)
- throws RemoteException {
- final Bundle in = new Bundle();
- in.putParcelable(DocumentsContract.EXTRA_URI, documentUri);
-
- client.call(METHOD_DELETE_DOCUMENT, null, in);
- }
-
/**
* Copies the given document.
*
@@ -1438,32 +1379,23 @@
* document's copy.
* @return the copied document, or {@code null} if failed.
*/
- public static Uri copyDocument(ContentResolver resolver, Uri sourceDocumentUri,
+ public static Uri copyDocument(ContentInterface content, Uri sourceDocumentUri,
Uri targetParentDocumentUri) throws FileNotFoundException {
- final ContentProviderClient client = resolver.acquireUnstableContentProviderClient(
- sourceDocumentUri.getAuthority());
try {
- return copyDocument(client, sourceDocumentUri, targetParentDocumentUri);
+ final Bundle in = new Bundle();
+ in.putParcelable(DocumentsContract.EXTRA_URI, sourceDocumentUri);
+ in.putParcelable(DocumentsContract.EXTRA_TARGET_URI, targetParentDocumentUri);
+
+ final Bundle out = content.call(sourceDocumentUri.getAuthority(),
+ METHOD_COPY_DOCUMENT, null, in);
+ return out.getParcelable(DocumentsContract.EXTRA_URI);
} catch (Exception e) {
Log.w(TAG, "Failed to copy document", e);
- rethrowIfNecessary(resolver, e);
+ rethrowIfNecessary(e);
return null;
- } finally {
- ContentProviderClient.releaseQuietly(client);
}
}
- /** {@hide} */
- public static Uri copyDocument(ContentProviderClient client, Uri sourceDocumentUri,
- Uri targetParentDocumentUri) throws RemoteException {
- final Bundle in = new Bundle();
- in.putParcelable(DocumentsContract.EXTRA_URI, sourceDocumentUri);
- in.putParcelable(DocumentsContract.EXTRA_TARGET_URI, targetParentDocumentUri);
-
- final Bundle out = client.call(METHOD_COPY_DOCUMENT, null, in);
- return out.getParcelable(DocumentsContract.EXTRA_URI);
- }
-
/**
* Moves the given document under a new parent.
*
@@ -1473,35 +1405,24 @@
* document.
* @return the moved document, or {@code null} if failed.
*/
- public static Uri moveDocument(ContentResolver resolver, Uri sourceDocumentUri,
+ public static Uri moveDocument(ContentInterface content, Uri sourceDocumentUri,
Uri sourceParentDocumentUri, Uri targetParentDocumentUri) throws FileNotFoundException {
- final ContentProviderClient client = resolver.acquireUnstableContentProviderClient(
- sourceDocumentUri.getAuthority());
try {
- return moveDocument(client, sourceDocumentUri, sourceParentDocumentUri,
- targetParentDocumentUri);
+ final Bundle in = new Bundle();
+ in.putParcelable(DocumentsContract.EXTRA_URI, sourceDocumentUri);
+ in.putParcelable(DocumentsContract.EXTRA_PARENT_URI, sourceParentDocumentUri);
+ in.putParcelable(DocumentsContract.EXTRA_TARGET_URI, targetParentDocumentUri);
+
+ final Bundle out = content.call(sourceDocumentUri.getAuthority(),
+ METHOD_MOVE_DOCUMENT, null, in);
+ return out.getParcelable(DocumentsContract.EXTRA_URI);
} catch (Exception e) {
Log.w(TAG, "Failed to move document", e);
- rethrowIfNecessary(resolver, e);
+ rethrowIfNecessary(e);
return null;
- } finally {
- ContentProviderClient.releaseQuietly(client);
}
}
- /** {@hide} */
- @UnsupportedAppUsage
- public static Uri moveDocument(ContentProviderClient client, Uri sourceDocumentUri,
- Uri sourceParentDocumentUri, Uri targetParentDocumentUri) throws RemoteException {
- final Bundle in = new Bundle();
- in.putParcelable(DocumentsContract.EXTRA_URI, sourceDocumentUri);
- in.putParcelable(DocumentsContract.EXTRA_PARENT_URI, sourceParentDocumentUri);
- in.putParcelable(DocumentsContract.EXTRA_TARGET_URI, targetParentDocumentUri);
-
- final Bundle out = client.call(METHOD_MOVE_DOCUMENT, null, in);
- return out.getParcelable(DocumentsContract.EXTRA_URI);
- }
-
/**
* Removes the given document from a parent directory.
*
@@ -1512,58 +1433,40 @@
* @param parentDocumentUri parent document of the document to remove.
* @return true if the document was removed successfully.
*/
- public static boolean removeDocument(ContentResolver resolver, Uri documentUri,
+ public static boolean removeDocument(ContentInterface content, Uri documentUri,
Uri parentDocumentUri) throws FileNotFoundException {
- final ContentProviderClient client = resolver.acquireUnstableContentProviderClient(
- documentUri.getAuthority());
try {
- removeDocument(client, documentUri, parentDocumentUri);
+ final Bundle in = new Bundle();
+ in.putParcelable(DocumentsContract.EXTRA_URI, documentUri);
+ in.putParcelable(DocumentsContract.EXTRA_PARENT_URI, parentDocumentUri);
+
+ content.call(documentUri.getAuthority(),
+ METHOD_REMOVE_DOCUMENT, null, in);
return true;
} catch (Exception e) {
Log.w(TAG, "Failed to remove document", e);
- rethrowIfNecessary(resolver, e);
+ rethrowIfNecessary(e);
return false;
- } finally {
- ContentProviderClient.releaseQuietly(client);
}
}
- /** {@hide} */
- public static void removeDocument(ContentProviderClient client, Uri documentUri,
- Uri parentDocumentUri) throws RemoteException {
- final Bundle in = new Bundle();
- in.putParcelable(DocumentsContract.EXTRA_URI, documentUri);
- in.putParcelable(DocumentsContract.EXTRA_PARENT_URI, parentDocumentUri);
-
- client.call(METHOD_REMOVE_DOCUMENT, null, in);
- }
-
/**
* Ejects the given root. It throws {@link IllegalStateException} when ejection failed.
*
* @param rootUri root with {@link Root#FLAG_SUPPORTS_EJECT} to be ejected
*/
- public static void ejectRoot(ContentResolver resolver, Uri rootUri) {
- final ContentProviderClient client = resolver.acquireUnstableContentProviderClient(
- rootUri.getAuthority());
+ public static void ejectRoot(ContentInterface content, Uri rootUri) {
try {
- ejectRoot(client, rootUri);
+ final Bundle in = new Bundle();
+ in.putParcelable(DocumentsContract.EXTRA_URI, rootUri);
+
+ content.call(rootUri.getAuthority(),
+ METHOD_EJECT_ROOT, null, in);
} catch (RemoteException e) {
e.rethrowAsRuntimeException();
- } finally {
- ContentProviderClient.releaseQuietly(client);
}
}
- /** {@hide} */
- public static void ejectRoot(ContentProviderClient client, Uri rootUri)
- throws RemoteException {
- final Bundle in = new Bundle();
- in.putParcelable(DocumentsContract.EXTRA_URI, rootUri);
-
- client.call(METHOD_EJECT_ROOT, null, in);
- }
-
/**
* Returns metadata associated with the document. The type of metadata returned
* is specific to the document type. For example the data returned for an image
@@ -1594,67 +1497,22 @@
* @param documentUri a Document URI
* @return a Bundle of Bundles.
*/
- public static Bundle getDocumentMetadata(ContentResolver resolver, Uri documentUri)
+ public static Bundle getDocumentMetadata(ContentInterface content, Uri documentUri)
throws FileNotFoundException {
- final ContentProviderClient client = resolver.acquireUnstableContentProviderClient(
- documentUri.getAuthority());
-
try {
- return getDocumentMetadata(client, documentUri);
+ final Bundle in = new Bundle();
+ in.putParcelable(EXTRA_URI, documentUri);
+
+ return content.call(documentUri.getAuthority(),
+ METHOD_GET_DOCUMENT_METADATA, null, in);
} catch (Exception e) {
Log.w(TAG, "Failed to get document metadata");
- rethrowIfNecessary(resolver, e);
+ rethrowIfNecessary(e);
return null;
- } finally {
- ContentProviderClient.releaseQuietly(client);
}
}
/**
- * Returns metadata associated with the document. The type of metadata returned
- * is specific to the document type. For example the data returned for an image
- * file will likely consist primarily or soley of EXIF metadata.
- *
- * <p>The returned {@link Bundle} will contain zero or more entries depending
- * on the type of data supported by the document provider.
- *
- * <ol>
- * <li>A {@link DocumentsContract.METADATA_TYPES} containing a {@code String[]} value.
- * The string array identifies the type or types of metadata returned. Each
- * value in the can be used to access a {@link Bundle} of data
- * containing that type of data.
- * <li>An entry each for each type of returned metadata. Each set of metadata is
- * itself represented as a bundle and accessible via a string key naming
- * the type of data.
- * </ol>
- *
- * <p>Example:
- * <p><pre><code>
- * Bundle metadata = DocumentsContract.getDocumentMetadata(client, imageDocUri, tags);
- * if (metadata.containsKey(DocumentsContract.METADATA_EXIF)) {
- * Bundle exif = metadata.getBundle(DocumentsContract.METADATA_EXIF);
- * int imageLength = exif.getInt(ExifInterface.TAG_IMAGE_LENGTH);
- * }
- * </code></pre>
- *
- * @param documentUri a Document URI
- * @return a Bundle of Bundles.
- * {@hide}
- */
- public static Bundle getDocumentMetadata(
- ContentProviderClient client, Uri documentUri) throws RemoteException {
- final Bundle in = new Bundle();
- in.putParcelable(EXTRA_URI, documentUri);
-
- final Bundle out = client.call(METHOD_GET_DOCUMENT_METADATA, null, in);
-
- if (out == null) {
- throw new RemoteException("Failed to get a response from getDocumentMetadata");
- }
- return out;
- }
-
- /**
* Finds the canonical path from the top of the document tree.
*
* The {@link Path#getPath()} of the return value contains the document ID
@@ -1667,52 +1525,25 @@
* @return the path of the document, or {@code null} if failed.
* @see DocumentsProvider#findDocumentPath(String, String)
*/
- public static Path findDocumentPath(ContentResolver resolver, Uri treeUri)
+ public static Path findDocumentPath(ContentInterface content, Uri treeUri)
throws FileNotFoundException {
checkArgument(isTreeUri(treeUri), treeUri + " is not a tree uri.");
- final ContentProviderClient client = resolver.acquireUnstableContentProviderClient(
- treeUri.getAuthority());
try {
- return findDocumentPath(client, treeUri);
+ final Bundle in = new Bundle();
+ in.putParcelable(DocumentsContract.EXTRA_URI, treeUri);
+
+ final Bundle out = content.call(treeUri.getAuthority(),
+ METHOD_FIND_DOCUMENT_PATH, null, in);
+ return out.getParcelable(DocumentsContract.EXTRA_RESULT);
} catch (Exception e) {
Log.w(TAG, "Failed to find path", e);
- rethrowIfNecessary(resolver, e);
+ rethrowIfNecessary(e);
return null;
- } finally {
- ContentProviderClient.releaseQuietly(client);
}
}
/**
- * Finds the canonical path. If uri is a document uri returns path from a root and
- * its associated root id. If uri is a tree uri returns the path from the top of
- * the tree. The {@link Path#getPath()} of the return value contains document ID
- * starts from the top of the tree or the root document to the requested document,
- * both inclusive.
- *
- * Callers can expect the root ID returned from multiple calls to this method is
- * consistent.
- *
- * @param uri uri of the document which path is requested. It can be either a
- * plain document uri or a tree uri.
- * @return the path of the document.
- * @see DocumentsProvider#findDocumentPath(String, String)
- *
- * {@hide}
- */
- public static Path findDocumentPath(ContentProviderClient client, Uri uri)
- throws RemoteException {
-
- final Bundle in = new Bundle();
- in.putParcelable(DocumentsContract.EXTRA_URI, uri);
-
- final Bundle out = client.call(METHOD_FIND_DOCUMENT_PATH, null, in);
-
- return out.getParcelable(DocumentsContract.EXTRA_RESULT);
- }
-
- /**
* Creates an intent for obtaining a web link for the specified document.
*
* <p>Note, that due to internal limitations, if there is already a web link
@@ -1763,40 +1594,29 @@
* @see DocumentsProvider#createWebLinkIntent(String, Bundle)
* @see Intent#EXTRA_EMAIL
*/
- public static IntentSender createWebLinkIntent(ContentResolver resolver, Uri uri,
+ public static IntentSender createWebLinkIntent(ContentInterface content, Uri uri,
Bundle options) throws FileNotFoundException {
- final ContentProviderClient client = resolver.acquireUnstableContentProviderClient(
- uri.getAuthority());
try {
- return createWebLinkIntent(client, uri, options);
+ final Bundle in = new Bundle();
+ in.putParcelable(DocumentsContract.EXTRA_URI, uri);
+
+ // Options may be provider specific, so put them in a separate bundle to
+ // avoid overriding the Uri.
+ if (options != null) {
+ in.putBundle(EXTRA_OPTIONS, options);
+ }
+
+ final Bundle out = content.call(uri.getAuthority(),
+ METHOD_CREATE_WEB_LINK_INTENT, null, in);
+ return out.getParcelable(DocumentsContract.EXTRA_RESULT);
} catch (Exception e) {
Log.w(TAG, "Failed to create a web link intent", e);
- rethrowIfNecessary(resolver, e);
+ rethrowIfNecessary(e);
return null;
- } finally {
- ContentProviderClient.releaseQuietly(client);
}
}
/**
- * {@hide}
- */
- public static IntentSender createWebLinkIntent(ContentProviderClient client, Uri uri,
- Bundle options) throws RemoteException {
- final Bundle in = new Bundle();
- in.putParcelable(DocumentsContract.EXTRA_URI, uri);
-
- // Options may be provider specific, so put them in a separate bundle to
- // avoid overriding the Uri.
- if (options != null) {
- in.putBundle(EXTRA_OPTIONS, options);
- }
-
- final Bundle out = client.call(METHOD_CREATE_WEB_LINK_INTENT, null, in);
- return out.getParcelable(DocumentsContract.EXTRA_RESULT);
- }
-
- /**
* Open the given image for thumbnail purposes, using any embedded EXIF
* thumbnail if available, and providing orientation hints from the parent
* image.
@@ -1836,10 +1656,9 @@
return new AssetFileDescriptor(pfd, 0, AssetFileDescriptor.UNKNOWN_LENGTH, extras);
}
- private static void rethrowIfNecessary(ContentResolver resolver, Exception e)
- throws FileNotFoundException {
+ private static void rethrowIfNecessary(Exception e) throws FileNotFoundException {
// We only want to throw applications targetting O and above
- if (resolver.getTargetSdkVersion() >= Build.VERSION_CODES.O) {
+ if (VMRuntime.getRuntime().getTargetSdkVersion() >= Build.VERSION_CODES.O) {
if (e instanceof ParcelableException) {
((ParcelableException) e).maybeRethrow(FileNotFoundException.class);
} else if (e instanceof RemoteException) {
diff --git a/core/java/android/provider/MediaStore.java b/core/java/android/provider/MediaStore.java
index 0299e41..1451165 100644
--- a/core/java/android/provider/MediaStore.java
+++ b/core/java/android/provider/MediaStore.java
@@ -16,11 +16,15 @@
package android.provider;
+import android.annotation.BytesLong;
import android.annotation.IntRange;
import android.annotation.NonNull;
import android.annotation.Nullable;
+import android.annotation.RequiresPermission;
import android.annotation.SdkConstant;
import android.annotation.SdkConstant.SdkConstantType;
+import android.annotation.SystemApi;
+import android.annotation.TestApi;
import android.annotation.UnsupportedAppUsage;
import android.app.Activity;
import android.app.AppGlobals;
@@ -102,6 +106,11 @@
/** {@hide} */
public static final String GET_MEDIA_URI_CALL = "get_media_uri";
+ /** {@hide} */
+ public static final String GET_CONTRIBUTED_MEDIA_CALL = "get_contributed_media";
+ /** {@hide} */
+ public static final String DELETE_CONTRIBUTED_MEDIA_CALL = "delete_contributed_media";
+
/**
* This is for internal use by the media scanner only.
* Name of the (optional) Uri parameter that determines whether to skip deleting
@@ -2865,4 +2874,47 @@
throw e.rethrowAsRuntimeException();
}
}
+
+ /**
+ * Calculate size of media contributed by given package under the calling
+ * user. The meaning of "contributed" means it won't automatically be
+ * deleted when the app is uninstalled.
+ *
+ * @hide
+ */
+ @SystemApi
+ @TestApi
+ @RequiresPermission(android.Manifest.permission.CLEAR_APP_USER_DATA)
+ public static @BytesLong long getContributedMediaSize(Context context, String packageName) {
+ try (ContentProviderClient client = context.getContentResolver()
+ .acquireContentProviderClient(AUTHORITY)) {
+ final Bundle in = new Bundle();
+ in.putString(Intent.EXTRA_PACKAGE_NAME, packageName);
+ final Bundle out = client.call(GET_CONTRIBUTED_MEDIA_CALL, null, in);
+ return out.getLong(Intent.EXTRA_INDEX);
+ } catch (RemoteException e) {
+ throw e.rethrowAsRuntimeException();
+ }
+ }
+
+ /**
+ * Delete all media contributed by given package under the calling user. The
+ * meaning of "contributed" means it won't automatically be deleted when the
+ * app is uninstalled.
+ *
+ * @hide
+ */
+ @SystemApi
+ @TestApi
+ @RequiresPermission(android.Manifest.permission.CLEAR_APP_USER_DATA)
+ public static void deleteContributedMedia(Context context, String packageName) {
+ try (ContentProviderClient client = context.getContentResolver()
+ .acquireContentProviderClient(AUTHORITY)) {
+ final Bundle in = new Bundle();
+ in.putString(Intent.EXTRA_PACKAGE_NAME, packageName);
+ client.call(DELETE_CONTRIBUTED_MEDIA_CALL, null, in);
+ } catch (RemoteException e) {
+ throw e.rethrowAsRuntimeException();
+ }
+ }
}
diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java
index 64aa088..de6afcb 100644
--- a/core/java/android/provider/Settings.java
+++ b/core/java/android/provider/Settings.java
@@ -1680,6 +1680,11 @@
*/
public static final String CALL_METHOD_TAG_KEY = "_tag";
+ /**
+ * @hide - String argument extra to the fast-path call()-based requests
+ */
+ public static final String CALL_METHOD_PREFIX_KEY = "_prefix";
+
/** @hide - Private call() method to write to 'system' table */
public static final String CALL_METHOD_PUT_SYSTEM = "PUT_system";
@@ -1701,15 +1706,18 @@
/** @hide - Private call() method to delete from the 'global' table */
public static final String CALL_METHOD_DELETE_GLOBAL = "DELETE_global";
+ /** @hide - Private call() method to reset to defaults the 'configuration' table */
+ public static final String CALL_METHOD_DELETE_CONFIG = "DELETE_config";
+
+ /** @hide - Private call() method to reset to defaults the 'secure' table */
+ public static final String CALL_METHOD_RESET_SECURE = "RESET_secure";
+
/** @hide - Private call() method to reset to defaults the 'global' table */
public static final String CALL_METHOD_RESET_GLOBAL = "RESET_global";
/** @hide - Private call() method to reset to defaults the 'configuration' table */
public static final String CALL_METHOD_RESET_CONFIG = "RESET_config";
- /** @hide - Private call() method to reset to defaults the 'secure' table */
- public static final String CALL_METHOD_RESET_SECURE = "RESET_secure";
-
/** @hide - Private call() method to query the 'system' table */
public static final String CALL_METHOD_LIST_SYSTEM = "LIST_system";
@@ -1719,6 +1727,9 @@
/** @hide - Private call() method to query the 'global' table */
public static final String CALL_METHOD_LIST_GLOBAL = "LIST_global";
+ /** @hide - Private call() method to reset to defaults the 'configuration' table */
+ public static final String CALL_METHOD_LIST_CONFIG = "LIST_config";
+
/**
* Activity Extra: Limit available options in launched activity based on the given authority.
* <p>
@@ -2044,7 +2055,8 @@
arg.putBoolean(CALL_METHOD_MAKE_DEFAULT_KEY, true);
}
IContentProvider cp = mProviderHolder.getProvider(cr);
- cp.call(cr.getPackageName(), mCallSetCommand, name, arg);
+ cp.call(cr.getPackageName(), mProviderHolder.mUri.getAuthority(),
+ mCallSetCommand, name, arg);
} catch (RemoteException e) {
Log.w(TAG, "Can't set key " + name + " in " + mUri, e);
return false;
@@ -2117,12 +2129,14 @@
if (Settings.isInSystemServer() && Binder.getCallingUid() != Process.myUid()) {
final long token = Binder.clearCallingIdentity();
try {
- b = cp.call(cr.getPackageName(), mCallGetCommand, name, args);
+ b = cp.call(cr.getPackageName(), mProviderHolder.mUri.getAuthority(),
+ mCallGetCommand, name, args);
} finally {
Binder.restoreCallingIdentity(token);
}
} else {
- b = cp.call(cr.getPackageName(), mCallGetCommand, name, args);
+ b = cp.call(cr.getPackageName(), mProviderHolder.mUri.getAuthority(),
+ mCallGetCommand, name, args);
}
if (b != null) {
String value = b.getString(Settings.NameValueTable.VALUE);
@@ -5112,7 +5126,8 @@
}
arg.putInt(CALL_METHOD_RESET_MODE_KEY, mode);
IContentProvider cp = sProviderHolder.getProvider(resolver);
- cp.call(resolver.getPackageName(), CALL_METHOD_RESET_SECURE, null, arg);
+ cp.call(resolver.getPackageName(), sProviderHolder.mUri.getAuthority(),
+ CALL_METHOD_RESET_SECURE, null, arg);
} catch (RemoteException e) {
Log.w(TAG, "Can't reset do defaults for " + CONTENT_URI, e);
}
@@ -11863,10 +11878,26 @@
public static final String GPU_DEBUG_APP = "gpu_debug_app";
/**
- * App should try to use ANGLE
+ * Force all PKGs to use ANGLE, regardless of any other settings
+ * The value is a boolean (1 or 0).
* @hide
*/
- public static final String ANGLE_ENABLED_APP = "angle_enabled_app";
+ public static final String GLOBAL_SETTINGS_ANGLE_GL_DRIVER_ALL_ANGLE =
+ "angle_gl_driver_all_angle";
+
+ /**
+ * List of PKGs that have an OpenGL driver selected
+ * @hide
+ */
+ public static final String GLOBAL_SETTINGS_ANGLE_GL_DRIVER_SELECTION_PKGS =
+ "angle_gl_driver_selection_pkgs";
+
+ /**
+ * List of selected OpenGL drivers, corresponding to the PKGs in GLOBAL_SETTINGS_DRIVER_PKGS
+ * @hide
+ */
+ public static final String GLOBAL_SETTINGS_ANGLE_GL_DRIVER_SELECTION_VALUES =
+ "angle_gl_driver_selection_values";
/**
* App that is selected to use updated graphics driver.
@@ -13147,7 +13178,8 @@
}
arg.putInt(CALL_METHOD_RESET_MODE_KEY, mode);
IContentProvider cp = sProviderHolder.getProvider(resolver);
- cp.call(resolver.getPackageName(), CALL_METHOD_RESET_GLOBAL, null, arg);
+ cp.call(resolver.getPackageName(), sProviderHolder.mUri.getAuthority(),
+ CALL_METHOD_RESET_GLOBAL, null, arg);
} catch (RemoteException e) {
Log.w(TAG, "Can't reset do defaults for " + CONTENT_URI, e);
}
@@ -13671,6 +13703,22 @@
"smart_replies_in_notifications_flags";
/**
+ * Configuration flags for the automatic generation of smart replies and smart actions in
+ * notifications. This is encoded as a key=value list, separated by commas. Ex:
+ * "generate_replies=false,generate_actions=true".
+ *
+ * The following keys are supported:
+ *
+ * <pre>
+ * generate_replies (boolean)
+ * generate_actions (boolean)
+ * </pre>
+ * @hide
+ */
+ public static final String SMART_SUGGESTIONS_IN_NOTIFICATIONS_FLAGS =
+ "smart_suggestions_in_notifications_flags";
+
+ /**
* If nonzero, crashes in foreground processes will bring up a dialog.
* Otherwise, the process will be silently killed.
* @hide
@@ -13747,6 +13795,14 @@
"backup_agent_timeout_parameters";
/**
+ * Whether the backup system service supports multiple users (0 = disabled, 1 = enabled). If
+ * disabled, the service will only be active for the system user.
+ *
+ * @hide
+ */
+ public static final String BACKUP_MULTI_USER_ENABLED = "backup_multi_user_enabled";
+
+ /**
* Blacklist of GNSS satellites.
*
* This is a list of integers separated by commas to represent pairs of (constellation,
@@ -13926,7 +13982,8 @@
}
arg.putInt(CALL_METHOD_RESET_MODE_KEY, RESET_MODE_PACKAGE_DEFAULTS);
IContentProvider cp = sProviderHolder.getProvider(resolver);
- cp.call(resolver.getPackageName(), CALL_METHOD_RESET_CONFIG, null, arg);
+ cp.call(resolver.getPackageName(), sProviderHolder.mUri.getAuthority(),
+ CALL_METHOD_RESET_CONFIG, null, arg);
} catch (RemoteException e) {
Log.w(TAG, "Can't reset to defaults for " + CONTENT_URI, e);
}
diff --git a/core/java/android/service/autofill/AutofillFieldClassificationService.java b/core/java/android/service/autofill/AutofillFieldClassificationService.java
index 1cd76d2..bd3c3d3 100644
--- a/core/java/android/service/autofill/AutofillFieldClassificationService.java
+++ b/core/java/android/service/autofill/AutofillFieldClassificationService.java
@@ -175,7 +175,7 @@
public float[][] onGetScores(@Nullable String algorithm,
@Nullable Bundle algorithmOptions, @NonNull List<AutofillValue> actualValues,
@NonNull List<String> userDataValues) {
- Log.e(TAG, "service implementation (" + getClass() + " does not implement onGetScore()");
+ Log.e(TAG, "service implementation (" + getClass() + " does not implement onGetScores()");
return null;
}
diff --git a/core/java/android/service/autofill/FillResponse.java b/core/java/android/service/autofill/FillResponse.java
index 7bf1f83..d408e9a 100644
--- a/core/java/android/service/autofill/FillResponse.java
+++ b/core/java/android/service/autofill/FillResponse.java
@@ -84,6 +84,7 @@
private final @Nullable AutofillId[] mFieldClassificationIds;
private final int mFlags;
private int mRequestId;
+ private final @Nullable UserData mUserData;
private FillResponse(@NonNull Builder builder) {
mDatasets = (builder.mDatasets != null) ? new ParceledListSlice<>(builder.mDatasets) : null;
@@ -99,6 +100,7 @@
mFieldClassificationIds = builder.mFieldClassificationIds;
mFlags = builder.mFlags;
mRequestId = INVALID_REQUEST_ID;
+ mUserData = builder.mUserData;
}
/** @hide */
@@ -157,6 +159,11 @@
}
/** @hide */
+ public @Nullable UserData getUserData() {
+ return mUserData;
+ }
+
+ /** @hide */
@TestApi
public int getFlags() {
return mFlags;
@@ -198,6 +205,7 @@
private AutofillId[] mFieldClassificationIds;
private int mFlags;
private boolean mDestroyed;
+ private UserData mUserData;
/**
* Triggers a custom UI before before autofilling the screen with any data set in this
@@ -506,6 +514,21 @@
}
/**
+ * Sets a specific {@link UserData} for field classification for this request only.
+ *
+ * @return this builder
+ * @throws IllegalStateException if the FillResponse
+ * {@link #setAuthentication(AutofillId[], IntentSender, RemoteViews)
+ * requires authentication}.
+ */
+ public Builder setUserData(@NonNull UserData userData) {
+ throwIfDestroyed();
+ throwIfAuthenticationCalled();
+ mUserData = Preconditions.checkNotNull(userData);
+ return this;
+ }
+
+ /**
* Builds a new {@link FillResponse} instance.
*
* @throws IllegalStateException if any of the following conditions occur:
@@ -599,6 +622,9 @@
if (mFieldClassificationIds != null) {
builder.append(Arrays.toString(mFieldClassificationIds));
}
+ if (mUserData != null) {
+ builder.append(", userData=").append(mUserData);
+ }
return builder.append("]").toString();
}
@@ -621,6 +647,7 @@
parcel.writeParcelable(mPresentation, flags);
parcel.writeParcelable(mHeader, flags);
parcel.writeParcelable(mFooter, flags);
+ parcel.writeParcelable(mUserData, flags);
parcel.writeParcelableArray(mIgnoredIds, flags);
parcel.writeLong(mDisableDuration);
parcel.writeParcelableArray(mFieldClassificationIds, flags);
@@ -661,6 +688,10 @@
if (footer != null) {
builder.setFooter(footer);
}
+ final UserData userData = parcel.readParcelable(null);
+ if (userData != null) {
+ builder.setUserData(userData);
+ }
builder.setIgnoredIds(parcel.readParcelableArray(null, AutofillId.class));
final long disableDuration = parcel.readLong();
diff --git a/core/java/android/service/autofill/augmented/FillWindow.java b/core/java/android/service/autofill/augmented/FillWindow.java
index 9e3aba4..27df845 100644
--- a/core/java/android/service/autofill/augmented/FillWindow.java
+++ b/core/java/android/service/autofill/augmented/FillWindow.java
@@ -26,6 +26,7 @@
import android.service.autofill.augmented.PresentationParams.Area;
import android.util.Log;
import android.view.Gravity;
+import android.view.MotionEvent;
import android.view.View;
import android.view.ViewGroup;
import android.view.Window;
@@ -140,10 +141,24 @@
// TODO(b/111330312): make sure all touch events are handled, window is always closed,
// etc.
- mDialog = new Dialog(rootView.getContext());
+ mDialog = new Dialog(rootView.getContext()) {
+ @Override
+ public boolean onTouchEvent(MotionEvent event) {
+ if (event.getAction() == MotionEvent.ACTION_OUTSIDE) {
+ FillWindow.this.destroy();
+ }
+ return false;
+ }
+ };
mCloseGuard.open("destroy");
final Window window = mDialog.getWindow();
window.setType(WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY);
+ // Makes sure touch outside the dialog is received by the window behind the dialog.
+ window.addFlags(WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL);
+ // Makes sure the touch outside the dialog is received by the dialog to dismiss it.
+ window.addFlags(WindowManager.LayoutParams.FLAG_WATCH_OUTSIDE_TOUCH);
+ // Makes sure keyboard shows up.
+ window.addFlags(WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM);
final int height = rect.bottom - rect.top;
final int width = rect.right - rect.left;
diff --git a/core/java/android/view/inputmethod/InputMethodManager.java b/core/java/android/view/inputmethod/InputMethodManager.java
index 1340955..e57fdff 100644
--- a/core/java/android/view/inputmethod/InputMethodManager.java
+++ b/core/java/android/view/inputmethod/InputMethodManager.java
@@ -2354,17 +2354,19 @@
}
/**
- * Shows the input method chooser dialog.
+ * Shows the input method chooser dialog from system.
*
* @param showAuxiliarySubtypes Set true to show auxiliary input methods.
+ * @param displayId The ID of the display where the chooser dialog should be shown.
* @hide
*/
- public void showInputMethodPicker(boolean showAuxiliarySubtypes) {
+ @RequiresPermission(WRITE_SECURE_SETTINGS)
+ public void showInputMethodPickerFromSystem(boolean showAuxiliarySubtypes, int displayId) {
final int mode = showAuxiliarySubtypes
? SHOW_IM_PICKER_MODE_INCLUDE_AUXILIARY_SUBTYPES
: SHOW_IM_PICKER_MODE_EXCLUDE_AUXILIARY_SUBTYPES;
try {
- mService.showInputMethodPickerFromClient(mClient, mode);
+ mService.showInputMethodPickerFromSystem(mClient, mode, displayId);
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
@@ -2520,16 +2522,6 @@
*/
@Deprecated
public boolean switchToLastInputMethod(IBinder imeToken) {
- if (imeToken == null) {
- // Note: null token is allowed for callers that have WRITE_SECURE_SETTINGS permission.
- // Thus we cannot always rely on InputMethodPrivilegedOperationsRegistry unfortunately.
- // TODO(Bug 114488811): Consider deprecating null token rule.
- try {
- return mService.switchToPreviousInputMethod(imeToken);
- } catch (RemoteException e) {
- throw e.rethrowFromSystemServer();
- }
- }
return InputMethodPrivilegedOperationsRegistry.get(imeToken).switchToPreviousInputMethod();
}
@@ -2548,16 +2540,6 @@
*/
@Deprecated
public boolean switchToNextInputMethod(IBinder imeToken, boolean onlyCurrentIme) {
- if (imeToken == null) {
- // Note: null token is allowed for callers that have WRITE_SECURE_SETTINGS permission.
- // Thus we cannot always rely on InputMethodPrivilegedOperationsRegistry unfortunately.
- // TODO(Bug 114488811): Consider deprecating null token rule.
- try {
- return mService.switchToNextInputMethod(imeToken, onlyCurrentIme);
- } catch (RemoteException e) {
- throw e.rethrowFromSystemServer();
- }
- }
return InputMethodPrivilegedOperationsRegistry.get(imeToken)
.switchToNextInputMethod(onlyCurrentIme);
}
diff --git a/core/java/android/view/textclassifier/ConversationActions.java b/core/java/android/view/textclassifier/ConversationActions.java
index 1a7b911..04b94b0 100644
--- a/core/java/android/view/textclassifier/ConversationActions.java
+++ b/core/java/android/view/textclassifier/ConversationActions.java
@@ -30,6 +30,7 @@
import android.text.SpannedString;
import android.util.ArraySet;
+import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.util.Preconditions;
import java.lang.annotation.Retention;
@@ -654,6 +655,8 @@
@NonNull
@Hint
private final List<String> mHints;
+ @Nullable
+ private String mCallingPackageName;
private Request(
@NonNull List<Message> conversation,
@@ -666,15 +669,26 @@
mHints = hints;
}
- private Request(Parcel in) {
+ private static Request readFromParcel(Parcel in) {
List<Message> conversation = new ArrayList<>();
in.readParcelableList(conversation, null);
- mConversation = Collections.unmodifiableList(conversation);
- mTypeConfig = in.readParcelable(null);
- mMaxSuggestions = in.readInt();
+
+ TypeConfig typeConfig = in.readParcelable(null);
+
+ int maxSuggestions = in.readInt();
+
List<String> hints = new ArrayList<>();
in.readStringList(hints);
- mHints = Collections.unmodifiableList(hints);
+
+ String callingPackageName = in.readString();
+
+ Request request = new Request(
+ conversation,
+ typeConfig,
+ maxSuggestions,
+ hints);
+ request.setCallingPackageName(callingPackageName);
+ return request;
}
@Override
@@ -683,6 +697,7 @@
parcel.writeParcelable(mTypeConfig, flags);
parcel.writeInt(mMaxSuggestions);
parcel.writeStringList(mHints);
+ parcel.writeString(mCallingPackageName);
}
@Override
@@ -694,7 +709,7 @@
new Creator<Request>() {
@Override
public Request createFromParcel(Parcel in) {
- return new Request(in);
+ return readFromParcel(in);
}
@Override
@@ -730,6 +745,26 @@
return mHints;
}
+ /**
+ * Sets the name of the package that is sending this request.
+ * <p>
+ * Package-private for SystemTextClassifier's use.
+ * @hide
+ */
+ @VisibleForTesting(visibility = VisibleForTesting.Visibility.PACKAGE)
+ public void setCallingPackageName(@Nullable String callingPackageName) {
+ mCallingPackageName = callingPackageName;
+ }
+
+ /**
+ * Returns the name of the package that sent this request.
+ * This returns {@code null} if no calling package name is set.
+ */
+ @Nullable
+ public String getCallingPackageName() {
+ return mCallingPackageName;
+ }
+
/** Builder object to construct the {@link Request} object. */
public static final class Builder {
@NonNull
diff --git a/core/java/android/view/textclassifier/SystemTextClassifier.java b/core/java/android/view/textclassifier/SystemTextClassifier.java
index f8fce62..c24489c 100644
--- a/core/java/android/view/textclassifier/SystemTextClassifier.java
+++ b/core/java/android/view/textclassifier/SystemTextClassifier.java
@@ -60,7 +60,7 @@
mSettings = Preconditions.checkNotNull(settings);
mFallback = context.getSystemService(TextClassificationManager.class)
.getTextClassifier(TextClassifier.LOCAL);
- mPackageName = Preconditions.checkNotNull(context.getPackageName());
+ mPackageName = Preconditions.checkNotNull(context.getOpPackageName());
}
/**
@@ -72,6 +72,7 @@
Preconditions.checkNotNull(request);
Utils.checkMainThread();
try {
+ request.setCallingPackageName(mPackageName);
final TextSelectionCallback callback = new TextSelectionCallback();
mManagerService.onSuggestSelection(mSessionId, request, callback);
final TextSelection selection = callback.mReceiver.get();
@@ -93,6 +94,7 @@
Preconditions.checkNotNull(request);
Utils.checkMainThread();
try {
+ request.setCallingPackageName(mPackageName);
final TextClassificationCallback callback = new TextClassificationCallback();
mManagerService.onClassifyText(mSessionId, request, callback);
final TextClassification classification = callback.mReceiver.get();
@@ -150,6 +152,7 @@
Utils.checkMainThread();
try {
+ request.setCallingPackageName(mPackageName);
final TextLanguageCallback callback = new TextLanguageCallback();
mManagerService.onDetectLanguage(mSessionId, request, callback);
final TextLanguage textLanguage = callback.mReceiver.get();
@@ -168,6 +171,7 @@
Utils.checkMainThread();
try {
+ request.setCallingPackageName(mPackageName);
final ConversationActionsCallback callback = new ConversationActionsCallback();
mManagerService.onSuggestConversationActions(mSessionId, request, callback);
final ConversationActions conversationActions = callback.mReceiver.get();
diff --git a/core/java/android/view/textclassifier/TextClassification.java b/core/java/android/view/textclassifier/TextClassification.java
index e0910c0..d9f7965 100644
--- a/core/java/android/view/textclassifier/TextClassification.java
+++ b/core/java/android/view/textclassifier/TextClassification.java
@@ -37,11 +37,13 @@
import android.os.LocaleList;
import android.os.Parcel;
import android.os.Parcelable;
+import android.text.SpannedString;
import android.util.ArrayMap;
import android.view.View.OnClickListener;
import android.view.textclassifier.TextClassifier.EntityType;
import android.view.textclassifier.TextClassifier.Utils;
+import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.util.Preconditions;
import java.lang.annotation.Retention;
@@ -518,6 +520,7 @@
@Nullable private final LocaleList mDefaultLocales;
@Nullable private final ZonedDateTime mReferenceTime;
@NonNull private final Bundle mExtras;
+ @Nullable private String mCallingPackageName;
private Request(
CharSequence text,
@@ -578,6 +581,26 @@
}
/**
+ * Sets the name of the package that is sending this request.
+ * <p>
+ * For SystemTextClassifier's use.
+ * @hide
+ */
+ @VisibleForTesting(visibility = VisibleForTesting.Visibility.PACKAGE)
+ public void setCallingPackageName(@Nullable String callingPackageName) {
+ mCallingPackageName = callingPackageName;
+ }
+
+ /**
+ * Returns the name of the package that sent this request.
+ * This returns {@code null} if no calling package name is set.
+ */
+ @Nullable
+ public String getCallingPackageName() {
+ return mCallingPackageName;
+ }
+
+ /**
* Returns the extended data.
*
* <p><b>NOTE: </b>Each call to this method returns a new bundle copy so clients should
@@ -660,7 +683,8 @@
*/
@NonNull
public Request build() {
- return new Request(mText, mStartIndex, mEndIndex, mDefaultLocales, mReferenceTime,
+ return new Request(new SpannedString(mText), mStartIndex, mEndIndex,
+ mDefaultLocales, mReferenceTime,
mExtras == null ? Bundle.EMPTY : mExtras.deepCopy());
}
}
@@ -672,25 +696,37 @@
@Override
public void writeToParcel(Parcel dest, int flags) {
- dest.writeString(mText.toString());
+ dest.writeCharSequence(mText);
dest.writeInt(mStartIndex);
dest.writeInt(mEndIndex);
- dest.writeInt(mDefaultLocales != null ? 1 : 0);
- if (mDefaultLocales != null) {
- mDefaultLocales.writeToParcel(dest, flags);
- }
- dest.writeInt(mReferenceTime != null ? 1 : 0);
- if (mReferenceTime != null) {
- dest.writeString(mReferenceTime.toString());
- }
+ dest.writeParcelable(mDefaultLocales, flags);
+ dest.writeString(mReferenceTime == null ? null : mReferenceTime.toString());
+ dest.writeString(mCallingPackageName);
dest.writeBundle(mExtras);
}
+ private static Request readFromParcel(Parcel in) {
+ final CharSequence text = in.readCharSequence();
+ final int startIndex = in.readInt();
+ final int endIndex = in.readInt();
+ final LocaleList defaultLocales = in.readParcelable(null);
+ final String referenceTimeString = in.readString();
+ final ZonedDateTime referenceTime = referenceTimeString == null
+ ? null : ZonedDateTime.parse(referenceTimeString);
+ final String callingPackageName = in.readString();
+ final Bundle extras = in.readBundle();
+
+ final Request request = new Request(text, startIndex, endIndex,
+ defaultLocales, referenceTime, extras);
+ request.setCallingPackageName(callingPackageName);
+ return request;
+ }
+
public static final Parcelable.Creator<Request> CREATOR =
new Parcelable.Creator<Request>() {
@Override
public Request createFromParcel(Parcel in) {
- return new Request(in);
+ return readFromParcel(in);
}
@Override
@@ -698,15 +734,6 @@
return new Request[size];
}
};
-
- private Request(Parcel in) {
- mText = in.readString();
- mStartIndex = in.readInt();
- mEndIndex = in.readInt();
- mDefaultLocales = in.readInt() == 0 ? null : LocaleList.CREATOR.createFromParcel(in);
- mReferenceTime = in.readInt() == 0 ? null : ZonedDateTime.parse(in.readString());
- mExtras = in.readBundle();
- }
}
@Override
diff --git a/core/java/android/view/textclassifier/TextLanguage.java b/core/java/android/view/textclassifier/TextLanguage.java
index d28459e..b1609fc 100644
--- a/core/java/android/view/textclassifier/TextLanguage.java
+++ b/core/java/android/view/textclassifier/TextLanguage.java
@@ -26,6 +26,7 @@
import android.os.Parcelable;
import android.util.ArrayMap;
+import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.util.Preconditions;
import java.util.Locale;
@@ -90,7 +91,7 @@
* confidence to low confidence.
*
* @throws IndexOutOfBoundsException if the specified index is out of range.
- * @see #getLocaleCount() for the number of locales available.
+ * @see #getLocaleHypothesisCount() for the number of locales available.
*/
@NonNull
public ULocale getLocale(int index) {
@@ -222,11 +223,12 @@
};
private final CharSequence mText;
- private final Bundle mBundle;
+ private final Bundle mExtra;
+ @Nullable private String mCallingPackageName;
private Request(CharSequence text, Bundle bundle) {
mText = text;
- mBundle = bundle;
+ mExtra = bundle;
}
/**
@@ -238,6 +240,25 @@
}
/**
+ * Sets the name of the package that is sending this request.
+ * Package-private for SystemTextClassifier's use.
+ * @hide
+ */
+ @VisibleForTesting(visibility = VisibleForTesting.Visibility.PACKAGE)
+ public void setCallingPackageName(@Nullable String callingPackageName) {
+ mCallingPackageName = callingPackageName;
+ }
+
+ /**
+ * Returns the name of the package that sent this request.
+ * This returns null if no calling package name is set.
+ */
+ @Nullable
+ public String getCallingPackageName() {
+ return mCallingPackageName;
+ }
+
+ /**
* Returns a bundle containing non-structured extra information about this request.
*
* <p><b>NOTE: </b>Each call to this method returns a new bundle copy so clients should
@@ -246,7 +267,7 @@
*/
@NonNull
public Bundle getExtras() {
- return mBundle.deepCopy();
+ return mExtra.deepCopy();
}
@Override
@@ -257,13 +278,18 @@
@Override
public void writeToParcel(Parcel dest, int flags) {
dest.writeCharSequence(mText);
- dest.writeBundle(mBundle);
+ dest.writeString(mCallingPackageName);
+ dest.writeBundle(mExtra);
}
private static Request readFromParcel(Parcel in) {
- return new Request(
- in.readCharSequence(),
- in.readBundle());
+ final CharSequence text = in.readCharSequence();
+ final String callingPackageName = in.readString();
+ final Bundle extra = in.readBundle();
+
+ final Request request = new Request(text, extra);
+ request.setCallingPackageName(callingPackageName);
+ return request;
}
/**
diff --git a/core/java/android/view/textclassifier/TextLinks.java b/core/java/android/view/textclassifier/TextLinks.java
index 1e42c41..ab34178 100644
--- a/core/java/android/view/textclassifier/TextLinks.java
+++ b/core/java/android/view/textclassifier/TextLinks.java
@@ -30,6 +30,7 @@
import android.text.style.ClickableSpan;
import android.text.style.URLSpan;
import android.view.View;
+import android.view.textclassifier.TextClassifier.EntityConfig;
import android.view.textclassifier.TextClassifier.EntityType;
import android.widget.TextView;
@@ -205,27 +206,32 @@
private final EntityConfidence mEntityScores;
private final int mStart;
private final int mEnd;
- @Nullable final URLSpan mUrlSpan;
+ private final Bundle mExtras;
+ @Nullable private final URLSpan mUrlSpan;
/**
* Create a new TextLink.
*
* @param start The start index of the identified subsequence
* @param end The end index of the identified subsequence
- * @param entityScores A mapping of entity type to confidence score
+ * @param entityConfidence A mapping of entity type to confidence score
+ * @param extras A bundle containing custom data related to this TextLink
* @param urlSpan An optional URLSpan to delegate to. NOTE: Not parcelled
*
- * @throws IllegalArgumentException if entityScores is null or empty
+ * @throws IllegalArgumentException if {@code entityConfidence} is null or empty
+ * @throws IllegalArgumentException if {@code start} is greater than {@code end}
*/
- TextLink(int start, int end, Map<String, Float> entityScores,
- @Nullable URLSpan urlSpan) {
- Preconditions.checkNotNull(entityScores);
- Preconditions.checkArgument(!entityScores.isEmpty());
+ private TextLink(int start, int end, @NonNull EntityConfidence entityConfidence,
+ @NonNull Bundle extras, @Nullable URLSpan urlSpan) {
+ Preconditions.checkNotNull(entityConfidence);
+ Preconditions.checkArgument(!entityConfidence.getEntities().isEmpty());
Preconditions.checkArgument(start <= end);
+ Preconditions.checkNotNull(extras);
mStart = start;
mEnd = end;
- mEntityScores = new EntityConfidence(entityScores);
+ mEntityScores = entityConfidence;
mUrlSpan = urlSpan;
+ mExtras = extras;
}
/**
@@ -274,6 +280,13 @@
return mEntityScores.getConfidenceScore(entityType);
}
+ /**
+ * Returns a bundle containing custom data related to this TextLink.
+ */
+ public Bundle getExtras() {
+ return mExtras;
+ }
+
@Override
public String toString() {
return String.format(Locale.US,
@@ -291,13 +304,22 @@
mEntityScores.writeToParcel(dest, flags);
dest.writeInt(mStart);
dest.writeInt(mEnd);
+ dest.writeBundle(mExtras);
+ }
+
+ private static TextLink readFromParcel(Parcel in) {
+ final EntityConfidence entityConfidence = EntityConfidence.CREATOR.createFromParcel(in);
+ final int start = in.readInt();
+ final int end = in.readInt();
+ final Bundle extras = in.readBundle();
+ return new TextLink(start, end, entityConfidence, extras, null /* urlSpan */);
}
public static final Parcelable.Creator<TextLink> CREATOR =
new Parcelable.Creator<TextLink>() {
@Override
public TextLink createFromParcel(Parcel in) {
- return new TextLink(in);
+ return readFromParcel(in);
}
@Override
@@ -305,13 +327,6 @@
return new TextLink[size];
}
};
-
- private TextLink(Parcel in) {
- mEntityScores = EntityConfidence.CREATOR.createFromParcel(in);
- mStart = in.readInt();
- mEnd = in.readInt();
- mUrlSpan = null;
- }
}
/**
@@ -321,23 +336,21 @@
private final CharSequence mText;
@Nullable private final LocaleList mDefaultLocales;
- @Nullable private final TextClassifier.EntityConfig mEntityConfig;
+ @Nullable private final EntityConfig mEntityConfig;
private final boolean mLegacyFallback;
- private String mCallingPackageName;
+ @Nullable private String mCallingPackageName;
private final Bundle mExtras;
private Request(
CharSequence text,
LocaleList defaultLocales,
- TextClassifier.EntityConfig entityConfig,
+ EntityConfig entityConfig,
boolean legacyFallback,
- String callingPackageName,
Bundle extras) {
mText = text;
mDefaultLocales = defaultLocales;
mEntityConfig = entityConfig;
mLegacyFallback = legacyFallback;
- mCallingPackageName = callingPackageName;
mExtras = extras;
}
@@ -360,10 +373,10 @@
/**
* @return The config representing the set of entities to look for
- * @see Builder#setEntityConfig(TextClassifier.EntityConfig)
+ * @see Builder#setEntityConfig(EntityConfig)
*/
@Nullable
- public TextClassifier.EntityConfig getEntityConfig() {
+ public EntityConfig getEntityConfig() {
return mEntityConfig;
}
@@ -378,13 +391,26 @@
}
/**
- * Sets the name of the package that requested the links to get generated.
+ * Sets the name of the package that is sending this request.
+ * <p>
+ * Package-private for SystemTextClassifier's use.
+ * @hide
*/
- void setCallingPackageName(@Nullable String callingPackageName) {
+ @VisibleForTesting(visibility = VisibleForTesting.Visibility.PACKAGE)
+ public void setCallingPackageName(@Nullable String callingPackageName) {
mCallingPackageName = callingPackageName;
}
/**
+ * Returns the name of the package that sent this request.
+ * This returns {@code null} if no calling package name is set.
+ */
+ @Nullable
+ public String getCallingPackageName() {
+ return mCallingPackageName;
+ }
+
+ /**
* Returns the extended data.
*
* <p><b>NOTE: </b>Each call to this method returns a new bundle copy so clients should
@@ -404,9 +430,8 @@
private final CharSequence mText;
@Nullable private LocaleList mDefaultLocales;
- @Nullable private TextClassifier.EntityConfig mEntityConfig;
+ @Nullable private EntityConfig mEntityConfig;
private boolean mLegacyFallback = true; // Use legacy fall back by default.
- private String mCallingPackageName;
@Nullable private Bundle mExtras;
public Builder(@NonNull CharSequence text) {
@@ -434,7 +459,7 @@
* @return this builder
*/
@NonNull
- public Builder setEntityConfig(@Nullable TextClassifier.EntityConfig entityConfig) {
+ public Builder setEntityConfig(@Nullable EntityConfig entityConfig) {
mEntityConfig = entityConfig;
return this;
}
@@ -455,18 +480,6 @@
}
/**
- * Sets the name of the package that requested the links to get generated.
- *
- * @return this builder
- * @hide
- */
- @NonNull
- public Builder setCallingPackageName(@Nullable String callingPackageName) {
- mCallingPackageName = callingPackageName;
- return this;
- }
-
- /**
* Sets the extended data.
*
* @return this builder
@@ -483,21 +496,11 @@
public Request build() {
return new Request(
mText, mDefaultLocales, mEntityConfig,
- mLegacyFallback, mCallingPackageName,
+ mLegacyFallback,
mExtras == null ? Bundle.EMPTY : mExtras.deepCopy());
}
}
- /**
- * @return the name of the package that requested the links to get generated.
- * TODO: make available as system API
- * @hide
- */
- @Nullable
- public String getCallingPackageName() {
- return mCallingPackageName;
- }
-
@Override
public int describeContents() {
return 0;
@@ -506,23 +509,30 @@
@Override
public void writeToParcel(Parcel dest, int flags) {
dest.writeString(mText.toString());
- dest.writeInt(mDefaultLocales != null ? 1 : 0);
- if (mDefaultLocales != null) {
- mDefaultLocales.writeToParcel(dest, flags);
- }
- dest.writeInt(mEntityConfig != null ? 1 : 0);
- if (mEntityConfig != null) {
- mEntityConfig.writeToParcel(dest, flags);
- }
+ dest.writeParcelable(mDefaultLocales, flags);
+ dest.writeParcelable(mEntityConfig, flags);
dest.writeString(mCallingPackageName);
dest.writeBundle(mExtras);
}
+ private static Request readFromParcel(Parcel in) {
+ final String text = in.readString();
+ final LocaleList defaultLocales = in.readParcelable(null);
+ final EntityConfig entityConfig = in.readParcelable(null);
+ final String callingPackageName = in.readString();
+ final Bundle extras = in.readBundle();
+
+ final Request request = new Request(text, defaultLocales, entityConfig,
+ /* legacyFallback= */ true, extras);
+ request.setCallingPackageName(callingPackageName);
+ return request;
+ }
+
public static final Parcelable.Creator<Request> CREATOR =
new Parcelable.Creator<Request>() {
@Override
public Request createFromParcel(Parcel in) {
- return new Request(in);
+ return readFromParcel(in);
}
@Override
@@ -530,16 +540,6 @@
return new Request[size];
}
};
-
- private Request(Parcel in) {
- mText = in.readString();
- mDefaultLocales = in.readInt() == 0 ? null : LocaleList.CREATOR.createFromParcel(in);
- mEntityConfig = in.readInt() == 0
- ? null : TextClassifier.EntityConfig.CREATOR.createFromParcel(in);
- mLegacyFallback = true;
- mCallingPackageName = in.readString();
- mExtras = in.readBundle();
- }
}
/**
@@ -645,9 +645,20 @@
* @throws IllegalArgumentException if entityScores is null or empty.
*/
@NonNull
- public Builder addLink(int start, int end, Map<String, Float> entityScores) {
- mLinks.add(new TextLink(start, end, entityScores, null));
- return this;
+ public Builder addLink(int start, int end, @NonNull Map<String, Float> entityScores) {
+ return addLink(start, end, entityScores, Bundle.EMPTY, null);
+ }
+
+ /**
+ * Adds a TextLink.
+ *
+ * @see #addLink(int, int, Map)
+ * @param extras An optional bundle containing custom data related to this TextLink
+ */
+ @NonNull
+ public Builder addLink(int start, int end, @NonNull Map<String, Float> entityScores,
+ @NonNull Bundle extras) {
+ return addLink(start, end, entityScores, extras, null);
}
/**
@@ -655,9 +666,15 @@
* @param urlSpan An optional URLSpan to delegate to. NOTE: Not parcelled.
*/
@NonNull
- Builder addLink(int start, int end, Map<String, Float> entityScores,
+ Builder addLink(int start, int end, @NonNull Map<String, Float> entityScores,
@Nullable URLSpan urlSpan) {
- mLinks.add(new TextLink(start, end, entityScores, urlSpan));
+ return addLink(start, end, entityScores, Bundle.EMPTY, urlSpan);
+ }
+
+ private Builder addLink(int start, int end, @NonNull Map<String, Float> entityScores,
+ @NonNull Bundle extras, @Nullable URLSpan urlSpan) {
+ mLinks.add(new TextLink(
+ start, end, new EntityConfidence(entityScores), extras, urlSpan));
return this;
}
diff --git a/core/java/android/view/textclassifier/TextSelection.java b/core/java/android/view/textclassifier/TextSelection.java
index f236915..4a6f3e5 100644
--- a/core/java/android/view/textclassifier/TextSelection.java
+++ b/core/java/android/view/textclassifier/TextSelection.java
@@ -24,10 +24,12 @@
import android.os.LocaleList;
import android.os.Parcel;
import android.os.Parcelable;
+import android.text.SpannedString;
import android.util.ArrayMap;
import android.view.textclassifier.TextClassifier.EntityType;
import android.view.textclassifier.TextClassifier.Utils;
+import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.util.Preconditions;
import java.util.Locale;
@@ -209,6 +211,7 @@
@Nullable private final LocaleList mDefaultLocales;
private final boolean mDarkLaunchAllowed;
private final Bundle mExtras;
+ @Nullable private String mCallingPackageName;
private Request(
CharSequence text,
@@ -270,6 +273,26 @@
}
/**
+ * Sets the name of the package that is sending this request.
+ * <p>
+ * Package-private for SystemTextClassifier's use.
+ * @hide
+ */
+ @VisibleForTesting(visibility = VisibleForTesting.Visibility.PACKAGE)
+ public void setCallingPackageName(@Nullable String callingPackageName) {
+ mCallingPackageName = callingPackageName;
+ }
+
+ /**
+ * Returns the name of the package that sent this request.
+ * This returns {@code null} if no calling package name is set.
+ */
+ @Nullable
+ public String getCallingPackageName() {
+ return mCallingPackageName;
+ }
+
+ /**
* Returns the extended data.
*
* <p><b>NOTE: </b>Each call to this method returns a new bundle copy so clients should
@@ -355,7 +378,7 @@
*/
@NonNull
public Request build() {
- return new Request(mText, mStartIndex, mEndIndex,
+ return new Request(new SpannedString(mText), mStartIndex, mEndIndex,
mDefaultLocales, mDarkLaunchAllowed,
mExtras == null ? Bundle.EMPTY : mExtras.deepCopy());
}
@@ -368,21 +391,33 @@
@Override
public void writeToParcel(Parcel dest, int flags) {
- dest.writeString(mText.toString());
+ dest.writeCharSequence(mText);
dest.writeInt(mStartIndex);
dest.writeInt(mEndIndex);
- dest.writeInt(mDefaultLocales != null ? 1 : 0);
- if (mDefaultLocales != null) {
- mDefaultLocales.writeToParcel(dest, flags);
- }
+ dest.writeParcelable(mDefaultLocales, flags);
+ dest.writeString(mCallingPackageName);
dest.writeBundle(mExtras);
}
+ private static Request readFromParcel(Parcel in) {
+ final CharSequence text = in.readCharSequence();
+ final int startIndex = in.readInt();
+ final int endIndex = in.readInt();
+ final LocaleList defaultLocales = in.readParcelable(null);
+ final String callingPackageName = in.readString();
+ final Bundle extras = in.readBundle();
+
+ final Request request = new Request(text, startIndex, endIndex, defaultLocales,
+ /* darkLaunchAllowed= */ false, extras);
+ request.setCallingPackageName(callingPackageName);
+ return request;
+ }
+
public static final Parcelable.Creator<Request> CREATOR =
new Parcelable.Creator<Request>() {
@Override
public Request createFromParcel(Parcel in) {
- return new Request(in);
+ return readFromParcel(in);
}
@Override
@@ -390,15 +425,6 @@
return new Request[size];
}
};
-
- private Request(Parcel in) {
- mText = in.readString();
- mStartIndex = in.readInt();
- mEndIndex = in.readInt();
- mDefaultLocales = in.readInt() == 0 ? null : LocaleList.CREATOR.createFromParcel(in);
- mDarkLaunchAllowed = false;
- mExtras = in.readBundle();
- }
}
@Override
diff --git a/core/java/com/android/internal/app/ResolverActivity.java b/core/java/com/android/internal/app/ResolverActivity.java
index 46c6fa4..ef5eb6c 100644
--- a/core/java/com/android/internal/app/ResolverActivity.java
+++ b/core/java/com/android/internal/app/ResolverActivity.java
@@ -94,7 +94,7 @@
public class ResolverActivity extends Activity {
// Temporary flag for new chooser delegate behavior.
- boolean mEnableChooserDelegate = false;
+ boolean mEnableChooserDelegate = true;
protected ResolveListAdapter mAdapter;
private boolean mSafeForwardingMode;
@@ -887,6 +887,8 @@
chooserIntent.putExtra(ActivityTaskManager.EXTRA_IGNORE_TARGET_SECURITY,
ignoreTargetSecurity);
chooserIntent.putExtra(Intent.EXTRA_USER_ID, userId);
+ chooserIntent.addFlags(Intent.FLAG_ACTIVITY_FORWARD_RESULT
+ | Intent.FLAG_ACTIVITY_PREVIOUS_IS_TOP);
startActivity(chooserIntent);
} catch (RemoteException e) {
Log.e(TAG, e.toString());
diff --git a/core/java/com/android/internal/view/IInputMethodManager.aidl b/core/java/com/android/internal/view/IInputMethodManager.aidl
index 1e71bd1..f62c440 100644
--- a/core/java/com/android/internal/view/IInputMethodManager.aidl
+++ b/core/java/com/android/internal/view/IInputMethodManager.aidl
@@ -64,6 +64,8 @@
void showInputMethodPickerFromClient(in IInputMethodClient client,
int auxiliarySubtypeMode);
+ void showInputMethodPickerFromSystem(in IInputMethodClient client, int auxiliarySubtypeMode,
+ int displayId);
void showInputMethodAndSubtypeEnablerFromClient(in IInputMethodClient client, String topId);
boolean isInputMethodPickerShownForTest();
// TODO(Bug 114488811): this can be removed once we deprecate special null token rule.
@@ -74,10 +76,6 @@
boolean notifySuggestionPicked(in SuggestionSpan span, String originalString, int index);
InputMethodSubtype getCurrentInputMethodSubtype();
boolean setCurrentInputMethodSubtype(in InputMethodSubtype subtype);
- // TODO(Bug 114488811): this can be removed once we deprecate special null token rule.
- boolean switchToPreviousInputMethod(in IBinder token);
- // TODO(Bug 114488811): this can be removed once we deprecate special null token rule.
- boolean switchToNextInputMethod(in IBinder token, boolean onlyCurrentIme);
void setAdditionalInputMethodSubtypes(String id, in InputMethodSubtype[] subtypes);
// This is kept due to @UnsupportedAppUsage.
// TODO(Bug 113914148): Consider removing this.
diff --git a/core/java/com/android/internal/widget/LockPatternUtils.java b/core/java/com/android/internal/widget/LockPatternUtils.java
index c96bacd..d5dc703 100644
--- a/core/java/com/android/internal/widget/LockPatternUtils.java
+++ b/core/java/com/android/internal/widget/LockPatternUtils.java
@@ -840,6 +840,11 @@
+ "of length " + MIN_LOCK_PASSWORD_SIZE);
}
+ if (requestedQuality < PASSWORD_QUALITY_NUMERIC) {
+ throw new IllegalArgumentException("quality must be at least NUMERIC, but was "
+ + requestedQuality);
+ }
+
final int currentQuality = getKeyguardStoredPasswordQuality(userHandle);
setKeyguardStoredPasswordQuality(
computePasswordQuality(CREDENTIAL_TYPE_PASSWORD, password, requestedQuality),
diff --git a/core/jni/android_media_AudioTrack.cpp b/core/jni/android_media_AudioTrack.cpp
index d927972..7ebb2b2 100644
--- a/core/jni/android_media_AudioTrack.cpp
+++ b/core/jni/android_media_AudioTrack.cpp
@@ -23,8 +23,6 @@
#include <nativehelper/JniConstants.h>
#include "core_jni_helpers.h"
-#include <nativehelper/ScopedBytes.h>
-
#include <utils/Log.h>
#include <media/AudioSystem.h>
#include <media/AudioTrack.h>
@@ -712,7 +710,7 @@
// ----------------------------------------------------------------------------
static jint android_media_AudioTrack_write_native_bytes(JNIEnv *env, jobject thiz,
- jbyteArray javaBytes, jint byteOffset, jint sizeInBytes,
+ jobject javaByteBuffer, jint byteOffset, jint sizeInBytes,
jint javaAudioFormat, jboolean isWriteBlocking) {
//ALOGV("android_media_AudioTrack_write_native_bytes(offset=%d, sizeInBytes=%d) called",
// offsetInBytes, sizeInBytes);
@@ -723,13 +721,14 @@
return (jint)AUDIO_JAVA_INVALID_OPERATION;
}
- ScopedBytesRO bytes(env, javaBytes);
- if (bytes.get() == NULL) {
+ const jbyte* bytes =
+ reinterpret_cast<const jbyte*>(env->GetDirectBufferAddress(javaByteBuffer));
+ if (bytes == NULL) {
ALOGE("Error retrieving source of audio data to play, can't play");
return (jint)AUDIO_JAVA_BAD_VALUE;
}
- jint written = writeToTrack(lpTrack, javaAudioFormat, bytes.get(), byteOffset,
+ jint written = writeToTrack(lpTrack, javaAudioFormat, bytes, byteOffset,
sizeInBytes, isWriteBlocking == JNI_TRUE /* blocking */);
return written;
@@ -1308,7 +1307,7 @@
{"native_release", "()V", (void *)android_media_AudioTrack_release},
{"native_write_byte", "([BIIIZ)I",(void *)android_media_AudioTrack_writeArray<jbyteArray>},
{"native_write_native_bytes",
- "(Ljava/lang/Object;IIIZ)I",
+ "(Ljava/nio/ByteBuffer;IIIZ)I",
(void *)android_media_AudioTrack_write_native_bytes},
{"native_write_short", "([SIIIZ)I",(void *)android_media_AudioTrack_writeArray<jshortArray>},
{"native_write_float", "([FIIIZ)I",(void *)android_media_AudioTrack_writeArray<jfloatArray>},
diff --git a/core/jni/android_os_GraphicsEnvironment.cpp b/core/jni/android_os_GraphicsEnvironment.cpp
index b1a9866..06625b3 100644
--- a/core/jni/android_os_GraphicsEnvironment.cpp
+++ b/core/jni/android_os_GraphicsEnvironment.cpp
@@ -32,15 +32,16 @@
android::GraphicsEnv::getInstance().setDriverPath(pathChars.c_str());
}
-void setAngleInfo_native(JNIEnv* env, jobject clazz, jstring path, jstring appName, jboolean devOptIn,
+void setAngleInfo_native(JNIEnv* env, jobject clazz, jstring path, jstring appName, jstring devOptIn,
jobject rulesFd, jlong rulesOffset, jlong rulesLength) {
ScopedUtfChars pathChars(env, path);
ScopedUtfChars appNameChars(env, appName);
+ ScopedUtfChars devOptInChars(env, devOptIn);
int rulesFd_native = jniGetFDFromFileDescriptor(env, rulesFd);
android::GraphicsEnv::getInstance().setAngleInfo(pathChars.c_str(), appNameChars.c_str(),
- devOptIn, rulesFd_native, rulesOffset, rulesLength);
+ devOptInChars.c_str(), rulesFd_native, rulesOffset, rulesLength);
}
void setLayerPaths_native(JNIEnv* env, jobject clazz, jobject classLoader, jstring layerPaths) {
@@ -67,7 +68,7 @@
const JNINativeMethod g_methods[] = {
{ "getCanLoadSystemLibraries", "()I", reinterpret_cast<void*>(getCanLoadSystemLibraries_native) },
{ "setDriverPath", "(Ljava/lang/String;)V", reinterpret_cast<void*>(setDriverPath) },
- { "setAngleInfo", "(Ljava/lang/String;Ljava/lang/String;ZLjava/io/FileDescriptor;JJ)V", reinterpret_cast<void*>(setAngleInfo_native) },
+ { "setAngleInfo", "(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/io/FileDescriptor;JJ)V", reinterpret_cast<void*>(setAngleInfo_native) },
{ "setLayerPaths", "(Ljava/lang/ClassLoader;Ljava/lang/String;)V", reinterpret_cast<void*>(setLayerPaths_native) },
{ "setDebugLayers", "(Ljava/lang/String;)V", reinterpret_cast<void*>(setDebugLayers_native) },
{ "setDebugLayersGLES", "(Ljava/lang/String;)V", reinterpret_cast<void*>(setDebugLayersGLES_native) },
diff --git a/core/proto/android/app/job/enums.proto b/core/proto/android/app/job/enums.proto
index 2290b2f..bba8328 100644
--- a/core/proto/android/app/job/enums.proto
+++ b/core/proto/android/app/job/enums.proto
@@ -30,4 +30,5 @@
STOP_REASON_PREEMPT = 2;
STOP_REASON_TIMEOUT = 3;
STOP_REASON_DEVICE_IDLE = 4;
+ STOP_REASON_DEVICE_THERMAL = 5;
}
diff --git a/core/proto/android/providers/settings/global.proto b/core/proto/android/providers/settings/global.proto
index 9620e4b..11bd43b 100644
--- a/core/proto/android/providers/settings/global.proto
+++ b/core/proto/android/providers/settings/global.proto
@@ -109,7 +109,15 @@
}
optional Autofill autofill = 140;
- optional SettingProto backup_agent_timeout_parameters = 18;
+ reserved 18; // Used to be backup_agent_timeout_parameters
+
+ message Backup {
+ option (android.msg_privacy).dest = DEST_EXPLICIT;
+
+ optional SettingProto backup_agent_timeout_parameters = 1;
+ optional SettingProto backup_multi_user_enabled = 2;
+ }
+ optional Backup backup = 146;
message Battery {
option (android.msg_privacy).dest = DEST_EXPLICIT;
@@ -417,16 +425,20 @@
// Ordered GPU debug layer list for Vulkan
// i.e. <layer1>:<layer2>:...:<layerN>
optional SettingProto debug_layers = 2 [ (android.privacy).dest = DEST_AUTOMATIC ];
- // App will load ANGLE instead of native GLES drivers.
- optional SettingProto angle_enabled_app = 3;
+ // ANGLE - Force all PKGs to use ANGLE, regardless of any other settings
+ optional SettingProto angle_gl_driver_all_angle = 3;
+ // ANGLE - List of PKGs that specify an OpenGL driver
+ optional SettingProto angle_gl_driver_selection_pkgs = 4;
+ // ANGLE - Corresponding OpenGL driver selection for the PKG
+ optional SettingProto angle_gl_driver_selection_values = 5;
// App that can provide layer libraries.
- optional SettingProto debug_layer_app = 4;
+ optional SettingProto debug_layer_app = 6;
// Ordered GPU debug layer list for GLES
// i.e. <layer1>:<layer2>:...:<layerN>
- optional SettingProto debug_layers_gles = 5;
+ optional SettingProto debug_layers_gles = 7;
// App opt in to load updated graphics driver instead of
// native graphcis driver through developer options.
- optional SettingProto updated_gfx_driver_dev_opt_in_app = 6;
+ optional SettingProto updated_gfx_driver_dev_opt_in_app = 8;
}
optional Gpu gpu = 59;
@@ -635,6 +647,9 @@
// separated by commas.
optional SettingProto snooze_options = 3 [ (android.privacy).dest = DEST_AUTOMATIC ];
optional SettingProto smart_replies_in_notifications_flags = 4 [ (android.privacy).dest = DEST_AUTOMATIC ];
+ // Configuration options for smart replies and smart actions in notifications. This is
+ // encoded as a key=value list separated by commas.
+ optional SettingProto smart_suggestions_in_notifications_flags = 5 [ (android.privacy).dest = DEST_AUTOMATIC ];
}
optional Notification notification = 82;
@@ -1000,5 +1015,5 @@
// Please insert fields in alphabetical order and group them into messages
// if possible (to avoid reaching the method limit).
- // Next tag = 146;
+ // Next tag = 147;
}
diff --git a/core/proto/android/server/jobscheduler.proto b/core/proto/android/server/jobscheduler.proto
index 231caab..c2bc7bf 100644
--- a/core/proto/android/server/jobscheduler.proto
+++ b/core/proto/android/server/jobscheduler.proto
@@ -41,6 +41,7 @@
optional int64 last_heartbeat_time_millis = 16;
optional int64 next_heartbeat_time_millis = 17;
optional bool in_parole = 18;
+ optional bool in_thermal = 19;
repeated int32 started_users = 2;
diff --git a/core/proto/android/stats/devicepolicy/device_policy_enums.proto b/core/proto/android/stats/devicepolicy/device_policy_enums.proto
index 8fbea12..5726d9a 100644
--- a/core/proto/android/stats/devicepolicy/device_policy_enums.proto
+++ b/core/proto/android/stats/devicepolicy/device_policy_enums.proto
@@ -44,7 +44,7 @@
SET_PERMISSION_GRANT_STATE = 19;
INSTALL_KEY_PAIR = 20;
INSTALL_CA_CERT = 21;
- ON_CHOOSE_KEY_ALIAS = 22;
+ CHOOSE_PRIVATE_KEY_ALIAS = 22;
REMOVE_KEY_PAIR = 23;
UNINSTALL_CA_CERTS = 24;
SET_CERT_INSTALLER_PACKAGE = 25;
@@ -68,12 +68,12 @@
SET_SHORT_SUPPORT_MESSAGE = 43;
SET_LONG_SUPPORT_MESSAGE = 44;
SET_CROSS_PROFILE_CONTACTS_SEARCH_DISABLED = 45;
- SET_CROSS_PROFILE_CALLER_DISABLED = 46;
+ SET_CROSS_PROFILE_CALLER_ID_DISABLED = 46;
SET_BLUETOOTH_CONTACT_SHARING_DISABLED = 47;
ADD_CROSS_PROFILE_INTENT_FILTER = 48;
ADD_CROSS_PROFILE_WIDGET_PROVIDER = 49;
SET_SYSTEM_UPDATE_POLICY = 50;
- SET_LOCKTASK_PACKAGES = 51;
+ SET_LOCKTASK_MODE_ENABLED = 51;
ADD_PERSISTENT_PREFERRED_ACTIVITY = 52;
REQUEST_BUGREPORT = 53;
GET_WIFI_MAC_ADDRESS = 54;
@@ -99,13 +99,13 @@
INSTALL_SYSTEM_UPDATE_ERROR = 74;
IS_MANAGED_KIOSK = 75;
IS_UNATTENDED_MANAGED_KIOSK = 76;
- PROVISIONING_TO_COMP = 77;
- PROVISIONING_FORCED_DO = 78;
+ PROVISIONING_MANAGED_PROFILE_ON_FULLY_MANAGED_DEVICE = 77;
+ PROVISIONING_PERSISTENT_DEVICE_OWNER = 78;
// existing Tron logs to be migrated to WestWorld
PROVISIONING_ENTRY_POINT_NFC = 79;
PROVISIONING_ENTRY_POINT_QR_CODE = 80;
- PROVISIONING_ENTRY_POINT_ZERO_TOUCH = 81;
+ PROVISIONING_ENTRY_POINT_CLOUD_ENROLLMENT = 81;
PROVISIONING_ENTRY_POINT_ADB = 82;
PROVISIONING_ENTRY_POINT_TRUSTED_SOURCE = 83;
PROVISIONING_DPC_PACKAGE_NAME = 84;
@@ -134,4 +134,9 @@
PROVISIONING_TERMS_ACTIVITY_TIME_MS = 107;
PROVISIONING_TERMS_COUNT = 108;
PROVISIONING_TERMS_READ = 109;
+
+ SEPARATE_PROFILE_CHALLENGE_CHANGED = 110;
+ SET_GLOBAL_SETTING = 111;
+ PM_IS_INSTALLER_DEVICE_OWNER_OR_AFFILIATED_PROFILE_OWNER = 112;
+ PM_UNINSTALL = 113;
}
diff --git a/core/proto/android/stats/docsui/docsui_enums.proto b/core/proto/android/stats/docsui/docsui_enums.proto
new file mode 100644
index 0000000..6cb606a
--- /dev/null
+++ b/core/proto/android/stats/docsui/docsui_enums.proto
@@ -0,0 +1,174 @@
+/*
+ * 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.
+ */
+
+syntax = "proto2";
+package android.stats.docsui;
+option java_multiple_files = true;
+
+enum LaunchAction {
+ UNKNOWN = 0;
+ OPEN = 1;
+ CREATE = 2;
+ GET_CONTENT = 3;
+ OPEN_TREE = 4;
+ PICK_COPY_DEST = 5;
+ BROWSE = 6;
+ OTHER = 7;
+}
+
+enum MimeType {
+ MIME_UNKNOWN = 0;
+ MIME_NONE = 1;
+ MIME_ANY = 2;
+ MIME_AUDIO = 3;
+ MIME_IMAGE = 4;
+ MIME_MESSAGE = 5;
+ MIME_MULTIPART = 6;
+ MIME_TEXT = 7;
+ MIME_VIDEO = 8;
+ MIME_OTHER = 9;
+}
+
+enum Root {
+ ROOT_UNKNOWN = 0;
+ ROOT_NONE = 1;
+ ROOT_OTHER_DOCS_PROVIDER = 2;
+ ROOT_AUDIO = 3;
+ ROOT_DEVICE_STORAGE = 4;
+ ROOT_DOWNLOADS = 5;
+ ROOT_HOME = 6;
+ ROOT_IMAGES = 7;
+ ROOT_RECENTS = 8;
+ ROOT_VIDEOS = 9;
+ ROOT_MTP = 10;
+ ROOT_THIRD_PARTY_APP = 11;
+}
+
+enum ContextScope {
+ SCOPE_UNKNOWN = 0;
+ SCOPE_FILES = 1;
+ SCOPE_PICKER = 2;
+}
+
+enum Provider {
+ PROVIDER_UNKNOWN = 0;
+ PROVIDER_SYSTEM = 1;
+ PROVIDER_EXTERNAL = 2;
+}
+
+enum FileOperation {
+ OP_UNKNOWN = 0;
+ OP_OTHER = 1;
+ OP_COPY = 2;
+ OP_COPY_INTRA_PROVIDER = 3;
+ OP_COPY_SYSTEM_PROVIDER = 4;
+ OP_COPY_EXTERNAL_PROVIDER = 5;
+ OP_MOVE = 6;
+ OP_MOVE_INTRA_PROVIDER = 7;
+ OP_MOVE_SYSTEM_PROVIDER = 8;
+ OP_MOVE_EXTERNAL_PROVIDER = 9;
+ OP_DELETE = 10;
+ OP_RENAME = 11;
+ OP_CREATE_DIR = 12;
+ OP_OTHER_ERROR = 13;
+ OP_DELETE_ERROR = 14;
+ OP_MOVE_ERROR = 15;
+ OP_COPY_ERROR = 16;
+ OP_RENAME_ERROR = 17;
+ OP_CREATE_DIR_ERROR = 18;
+ OP_COMPRESS_INTRA_PROVIDER = 19;
+ OP_COMPRESS_SYSTEM_PROVIDER = 20;
+ OP_COMPRESS_EXTERNAL_PROVIDER = 21;
+ OP_EXTRACT_INTRA_PROVIDER = 22;
+ OP_EXTRACT_SYSTEM_PROVIDER = 23;
+ OP_EXTRACT_EXTERNAL_PROVIDER = 24;
+ OP_COMPRESS_ERROR = 25;
+ OP_EXTRACT_ERROR = 26;
+}
+
+enum SubFileOperation {
+ SUB_OP_UNKNOWN = 0;
+ SUB_OP_QUERY_DOC = 1;
+ SUB_OP_QUERY_CHILD = 2;
+ SUB_OP_OPEN_FILE = 3;
+ SUB_OP_READ_FILE = 4;
+ SUB_OP_CREATE_DOC = 5;
+ SUB_OP_WRITE_FILE = 6;
+ SUB_OP_DELETE_DOC = 7;
+ SUB_OP_OBTAIN_STREAM_TYPE = 8;
+ SUB_OP_QUICK_MOVE = 9;
+ SUB_OP_QUICK_COPY = 10;
+}
+
+enum CopyMoveOpMode {
+ MODE_UNKNOWN = 0;
+ MODE_PROVIDER = 1;
+ MODE_CONVERTED = 2;
+ MODE_CONVENTIONAL = 3;
+}
+
+enum Authority {
+ AUTH_UNKNOWN = 0;
+ AUTH_OTHER = 1;
+ AUTH_MEDIA = 2;
+ AUTH_STORAGE_INTERNAL = 3;
+ AUTH_STORAGE_EXTERNAL = 4;
+ AUTH_DOWNLOADS = 5;
+ AUTH_MTP = 6;
+}
+
+enum UserAction {
+ ACTION_UNKNOWN = 0;
+ ACTION_OTHER = 1;
+ ACTION_GRID = 2;
+ ACTION_LIST = 3;
+ ACTION_SORT_NAME = 4;
+ ACTION_SORT_DATE = 5;
+ ACTION_SORT_SIZE = 6;
+ ACTION_SORT_TYPE = 7;
+ ACTION_SEARCH = 8;
+ ACTION_SHOW_SIZE = 9;
+ ACTION_HIDE_SIZE = 10;
+ ACTION_SETTINGS = 11;
+ ACTION_COPY_TO = 12;
+ ACTION_MOVE_TO = 13;
+ ACTION_DELETE = 14;
+ ACTION_RENAME = 15;
+ ACTION_CREATE_DIR = 16;
+ ACTION_SELECT_ALL = 17;
+ ACTION_SHARE = 18;
+ ACTION_OPEN = 19;
+ ACTION_SHOW_ADVANCED = 20;
+ ACTION_HIDE_ADVANCED = 21;
+ ACTION_NEW_WINDOW = 22;
+ ACTION_PASTE_CLIPBOARD = 23;
+ ACTION_COPY_CLIPBOARD = 24;
+ ACTION_DRAG_N_DROP = 25;
+ ACTION_DRAG_N_DROP_MULTI_WINDOW = 26;
+ ACTION_CUT_CLIPBOARD = 27;
+ ACTION_COMPRESS = 28;
+ ACTION_EXTRACT_TO = 29;
+ ACTION_VIEW_IN_APPLICATION = 30;
+ ACTION_INSPECTOR = 31;
+}
+
+enum InvalidScopedAccess {
+ SCOPED_DIR_ACCESS_UNKNOWN = 0;
+ SCOPED_DIR_ACCESS_INVALID_ARGUMENTS = 1;
+ SCOPED_DIR_ACCESS_INVALID_DIRECTORY = 2;
+ SCOPED_DIR_ACCESS_ERROR = 3;
+ SCOPED_DIR_ACCESS_DEPRECATED = 4;
+}
diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml
index 594ae6b..4dedd49 100644
--- a/core/res/AndroidManifest.xml
+++ b/core/res/AndroidManifest.xml
@@ -1595,7 +1595,7 @@
@hide This should only be used by ManagedProvisioning app.
-->
<permission android:name="android.permission.NETWORK_MANAGED_PROVISIONING"
- android:protectionLevel="signature|privileged" />
+ android:protectionLevel="signature" />
<!-- #SystemApi @hide Allows applications to access information about LoWPAN interfaces.
<p>Not for use by third-party applications. -->
@@ -1648,7 +1648,7 @@
@hide
-->
<permission android:name="android.permission.SUSPEND_APPS"
- android:protectionLevel="signature|privileged" />
+ android:protectionLevel="signature|wellbeing" />
<!-- Allows applications to discover and pair bluetooth devices.
<p>Protection level: normal
@@ -4086,10 +4086,10 @@
confirmation UI for full backup/restore -->
<uses-permission android:name="android.permission.CONFIRM_FULL_BACKUP"/>
- <!-- Allows the holder to access and manage instant applications on the device.
- @hide -->
+ <!-- @SystemApi Allows the holder to access and manage instant applications on the device.
+ @hide -->
<permission android:name="android.permission.ACCESS_INSTANT_APPS"
- android:protectionLevel="signature|installer|verifier" />
+ android:protectionLevel="signature|installer|verifier|wellbeing" />
<uses-permission android:name="android.permission.ACCESS_INSTANT_APPS"/>
<!-- Allows the holder to view the instant applications on the device.
diff --git a/core/res/res/values/attrs_manifest.xml b/core/res/res/values/attrs_manifest.xml
index 089c59f..f8004ea 100644
--- a/core/res/res/values/attrs_manifest.xml
+++ b/core/res/res/values/attrs_manifest.xml
@@ -268,6 +268,9 @@
<!-- Additional flag from base permission type: this permission can be automatically
granted to the system default text classifier -->
<flag name="textClassifier" value="0x10000" />
+ <!-- Additional flag from base permission type: this permission will be granted to the
+ wellbeing app, as defined by the OEM. -->
+ <flag name="wellbeing" value="0x20000" />
</attr>
<!-- Flags indicating more context for a permission group. -->
@@ -1394,6 +1397,29 @@
<attr name="usesNonSdkApi" format="boolean" />
+ <!-- Specify the type of foreground service. Apps targeting API
+ {@link android.os.Build.VERSION_CODES#Q} or later must specify foreground service type,
+ otherwise a SecurityException is thrown when
+ {@link android.app.Service#startForeground(int, Notification)} on this service is called.
+ -->
+ <attr name="foregroundServiceType">
+ <!-- Data (photo, file, account) upload/download, backup/restore, import/export, fetch,
+ transfer over network between device and cloud. -->
+ <enum name="sync" value="1" />
+ <!-- Music, video, news or other media play. -->
+ <enum name="mediaPlay" value="2" />
+ <!-- Ongoing phone call or video conference. -->
+ <enum name="phoneCall" value="3" />
+ <!-- GPS, map, navigation location update. -->
+ <enum name="location" value="4" />
+ <!-- Auto, bluetooth, TV or other devices connection, monitoring and interaction. -->
+ <enum name="deviceCompanion" value="5" />
+ <!-- Process that should not be interrupted, including installation, setup, photo
+ compression etc. -->
+ <enum name="ongoingProcess" value="6" />
+ </attr>
+
+
<!-- The <code>manifest</code> tag is the root of an
<code>AndroidManifest.xml</code> file,
describing the contents of an Android package (.apk) file. One
@@ -2242,6 +2268,8 @@
recommended to measure memory usage under typical workloads to determine
whether it makes sense to use this flag. -->
<attr name="useAppZygote" format="boolean" />
+ <!-- If this is a foreground service, specify its category. -->
+ <attr name="foregroundServiceType" />
</declare-styleable>
<!-- The <code>receiver</code> tag declares an
diff --git a/core/res/res/values/config.xml b/core/res/res/values/config.xml
index 62ec5c4..101f92b 100644
--- a/core/res/res/values/config.xml
+++ b/core/res/res/values/config.xml
@@ -3349,6 +3349,13 @@
See android.view.textclassifier.TextClassificationManager.
-->
<string name="config_defaultTextClassifierPackage" translatable="false"></string>
+
+ <!-- The package name for the default wellbeing app.
+ This package must be trusted, as it has the permissions to control other applications
+ on the device.
+ Example: "com.android.wellbeing"
+ -->
+ <string name="config_defaultWellbeingPackage" translatable="false"></string>
<!-- The package name for the system's content capture service.
This service must be trusted, as it can be activated without explicit consent of the user.
diff --git a/core/res/res/values/public.xml b/core/res/res/values/public.xml
index 5e8af62..d480121 100644
--- a/core/res/res/values/public.xml
+++ b/core/res/res/values/public.xml
@@ -2929,6 +2929,7 @@
<public name="dataUsedForMonetization" />
<public name="dataRetentionTime" />
<public name="selectionDividerHeight" />
+ <public name="foregroundServiceType" />
</public-group>
<public-group type="drawable" first-id="0x010800b4">
diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml
index 82a679e..b24cdba 100644
--- a/core/res/res/values/symbols.xml
+++ b/core/res/res/values/symbols.xml
@@ -3265,6 +3265,7 @@
<java-symbol type="string" name="notification_channel_do_not_disturb" />
<java-symbol type="string" name="config_defaultAutofillService" />
<java-symbol type="string" name="config_defaultTextClassifierPackage" />
+ <java-symbol type="string" name="config_defaultWellbeingPackage" />
<java-symbol type="string" name="config_defaultContentCaptureService" />
<java-symbol type="string" name="config_defaultAugmentedAutofillService" />
diff --git a/core/tests/coretests/src/android/provider/SettingsBackupTest.java b/core/tests/coretests/src/android/provider/SettingsBackupTest.java
index f1ed1c2..49a7555 100644
--- a/core/tests/coretests/src/android/provider/SettingsBackupTest.java
+++ b/core/tests/coretests/src/android/provider/SettingsBackupTest.java
@@ -248,6 +248,7 @@
Settings.Global.DYNAMIC_POWER_SAVINGS_ENABLED,
Settings.Global.DYNAMIC_POWER_SAVINGS_DISABLE_THRESHOLD,
Settings.Global.SMART_REPLIES_IN_NOTIFICATIONS_FLAGS,
+ Settings.Global.SMART_SUGGESTIONS_IN_NOTIFICATIONS_FLAGS,
Settings.Global.ENHANCED_4G_MODE_ENABLED,
Settings.Global.EPHEMERAL_COOKIE_MAX_SIZE_BYTES,
Settings.Global.ERROR_LOGCAT_PREFIX,
@@ -469,7 +470,9 @@
Settings.Global.GPU_DEBUG_APP,
Settings.Global.GPU_DEBUG_LAYERS,
Settings.Global.GPU_DEBUG_LAYERS_GLES,
- Settings.Global.ANGLE_ENABLED_APP,
+ Settings.Global.GLOBAL_SETTINGS_ANGLE_GL_DRIVER_ALL_ANGLE,
+ Settings.Global.GLOBAL_SETTINGS_ANGLE_GL_DRIVER_SELECTION_PKGS,
+ Settings.Global.GLOBAL_SETTINGS_ANGLE_GL_DRIVER_SELECTION_VALUES,
Settings.Global.UPDATED_GFX_DRIVER_DEV_OPT_IN_APP,
Settings.Global.GPU_DEBUG_LAYER_APP,
Settings.Global.ENABLE_GNSS_RAW_MEAS_FULL_TRACKING,
@@ -538,7 +541,8 @@
Settings.Global.OVERRIDE_SETTINGS_PROVIDER_RESTORE_ANY_VERSION,
Settings.Global.CHAINED_BATTERY_ATTRIBUTION_ENABLED,
Settings.Global.HIDDEN_API_BLACKLIST_EXEMPTIONS,
- Settings.Global.BACKUP_AGENT_TIMEOUT_PARAMETERS);
+ Settings.Global.BACKUP_AGENT_TIMEOUT_PARAMETERS,
+ Settings.Global.BACKUP_MULTI_USER_ENABLED);
private static final Set<String> BACKUP_BLACKLISTED_SECURE_SETTINGS =
newHashSet(
Settings.Secure.ACCESSIBILITY_SOFT_KEYBOARD_MODE,
diff --git a/core/tests/coretests/src/android/provider/SettingsProviderTest.java b/core/tests/coretests/src/android/provider/SettingsProviderTest.java
index 108585d..04e8802 100644
--- a/core/tests/coretests/src/android/provider/SettingsProviderTest.java
+++ b/core/tests/coretests/src/android/provider/SettingsProviderTest.java
@@ -16,6 +16,10 @@
package android.provider;
+import static org.hamcrest.Matchers.aMapWithSize;
+import static org.hamcrest.Matchers.greaterThanOrEqualTo;
+import static org.junit.Assert.assertThat;
+
import android.content.ContentResolver;
import android.content.ContentUris;
import android.content.ContentValues;
@@ -26,6 +30,7 @@
import android.content.pm.UserInfo;
import android.database.Cursor;
import android.net.Uri;
+import android.os.Bundle;
import android.os.UserHandle;
import android.os.UserManager;
import android.test.AndroidTestCase;
@@ -33,10 +38,19 @@
import android.test.suitebuilder.annotation.SmallTest;
import android.test.suitebuilder.annotation.Suppress;
+import java.util.HashMap;
import java.util.List;
+import java.util.Map;
/** Unit test for SettingsProvider. */
public class SettingsProviderTest extends AndroidTestCase {
+ /**
+ * TODO(b/113100523): Move this to DeviceConfig.java when it is added, and expose it as a System
+ * API.
+ */
+ private static final Uri CONFIG_CONTENT_URI =
+ Uri.parse("content://" + Settings.AUTHORITY + "/config");
+
@MediumTest
public void testNameValueCache() {
ContentResolver r = getContext().getContentResolver();
@@ -379,4 +393,109 @@
assertTrue(ssaid.equals(ssaid2));
}
+
+ @MediumTest
+ public void testCall_putAndGetConfig() {
+ ContentResolver r = getContext().getContentResolver();
+ String name = "key1";
+ String value = "value1";
+ String newValue = "value2";
+ Bundle args = new Bundle();
+ args.putString(Settings.NameValueTable.VALUE, value);
+
+ try {
+ // value is empty
+ Bundle results =
+ r.call(CONFIG_CONTENT_URI, Settings.CALL_METHOD_GET_CONFIG, name, null);
+ assertNull(results.get(Settings.NameValueTable.VALUE));
+
+ // save value
+ results = r.call(CONFIG_CONTENT_URI, Settings.CALL_METHOD_PUT_CONFIG, name, args);
+ assertNull(results);
+
+ // value is no longer empty
+ results = r.call(CONFIG_CONTENT_URI, Settings.CALL_METHOD_GET_CONFIG, name, null);
+ assertEquals(value, results.get(Settings.NameValueTable.VALUE));
+
+ // save new value
+ args.putString(Settings.NameValueTable.VALUE, newValue);
+ r.call(CONFIG_CONTENT_URI, Settings.CALL_METHOD_PUT_CONFIG, name, args);
+
+ // new value is returned
+ results = r.call(CONFIG_CONTENT_URI, Settings.CALL_METHOD_GET_CONFIG, name, null);
+ assertEquals(newValue, results.get(Settings.NameValueTable.VALUE));
+ } finally {
+ // clean up
+ r.call(CONFIG_CONTENT_URI, Settings.CALL_METHOD_DELETE_CONFIG, name, null);
+ }
+ }
+
+ @MediumTest
+ public void testCall_deleteConfig() {
+ ContentResolver r = getContext().getContentResolver();
+ String name = "key1";
+ String value = "value1";
+ Bundle args = new Bundle();
+ args.putString(Settings.NameValueTable.VALUE, value);
+
+ try {
+ // save value
+ r.call(CONFIG_CONTENT_URI, Settings.CALL_METHOD_PUT_CONFIG, name, args);
+
+ // get value
+ Bundle results =
+ r.call(CONFIG_CONTENT_URI, Settings.CALL_METHOD_GET_CONFIG, name, null);
+ assertEquals(value, results.get(Settings.NameValueTable.VALUE));
+
+ // delete value
+ results = r.call(CONFIG_CONTENT_URI, Settings.CALL_METHOD_DELETE_CONFIG, name, null);
+
+ // value is empty now
+ results = r.call(CONFIG_CONTENT_URI, Settings.CALL_METHOD_GET_CONFIG, name, null);
+ assertNull(results.get(Settings.NameValueTable.VALUE));
+ } finally {
+ // clean up
+ r.call(CONFIG_CONTENT_URI, Settings.CALL_METHOD_DELETE_CONFIG, name, null);
+ }
+ }
+
+ @MediumTest
+ public void testCall_listConfig() {
+ ContentResolver r = getContext().getContentResolver();
+ String prefix = "foo";
+ String newPrefix = "bar";
+ String name = prefix + "/" + "key1";
+ String newName = newPrefix + "/" + "key1";
+ String value = "value1";
+ String newValue = "value2";
+ Bundle args = new Bundle();
+ args.putString(Settings.NameValueTable.VALUE, value);
+
+ try {
+ // save both values
+ r.call(CONFIG_CONTENT_URI, Settings.CALL_METHOD_PUT_CONFIG, name, args);
+ args.putString(Settings.NameValueTable.VALUE, newValue);
+ r.call(CONFIG_CONTENT_URI, Settings.CALL_METHOD_PUT_CONFIG, newName, args);
+
+ // list all values
+ Bundle result = r.call(CONFIG_CONTENT_URI, Settings.CALL_METHOD_LIST_CONFIG,
+ null, null);
+ Map<String, String> keyValueMap =
+ (HashMap) result.getSerializable(Settings.NameValueTable.VALUE);
+ assertThat(keyValueMap.size(), greaterThanOrEqualTo(2));
+ assertEquals(value, keyValueMap.get(name));
+ assertEquals(newValue, keyValueMap.get(newName));
+
+ // list values for prefix
+ args.putString(Settings.CALL_METHOD_PREFIX_KEY, prefix);
+ result = r.call(CONFIG_CONTENT_URI, Settings.CALL_METHOD_LIST_CONFIG, null, args);
+ keyValueMap = (HashMap) result.getSerializable(Settings.NameValueTable.VALUE);
+ assertThat(keyValueMap, aMapWithSize(1));
+ assertEquals(value, keyValueMap.get(name));
+ } finally {
+ // clean up
+ r.call(CONFIG_CONTENT_URI, Settings.CALL_METHOD_DELETE_CONFIG, name, null);
+ r.call(CONFIG_CONTENT_URI, Settings.CALL_METHOD_DELETE_CONFIG, newName, null);
+ }
+ }
}
diff --git a/core/tests/coretests/src/android/view/textclassifier/TextClassificationTest.java b/core/tests/coretests/src/android/view/textclassifier/TextClassificationTest.java
index 91a5440..aaf7312 100644
--- a/core/tests/coretests/src/android/view/textclassifier/TextClassificationTest.java
+++ b/core/tests/coretests/src/android/view/textclassifier/TextClassificationTest.java
@@ -189,6 +189,7 @@
Instant.ofEpochMilli(946771200000L), // 2000-01-02
ZoneId.of("UTC"));
final String text = "text";
+ final String packageName = "packageName";
final TextClassification.Request reference =
new TextClassification.Request.Builder(text, 0, text.length())
@@ -196,6 +197,7 @@
.setReferenceTime(referenceTime)
.setExtras(BUNDLE)
.build();
+ reference.setCallingPackageName(packageName);
// Parcel and unparcel.
final Parcel parcel = Parcel.obtain();
@@ -204,12 +206,13 @@
final TextClassification.Request result =
TextClassification.Request.CREATOR.createFromParcel(parcel);
- assertEquals(text, result.getText());
+ assertEquals(text, result.getText().toString());
assertEquals(0, result.getStartIndex());
assertEquals(text.length(), result.getEndIndex());
assertEquals(referenceTime, result.getReferenceTime());
assertEquals("en-US,de-DE", result.getDefaultLocales().toLanguageTags());
assertEquals(referenceTime, result.getReferenceTime());
assertEquals(BUNDLE_VALUE, result.getExtras().getString(BUNDLE_KEY));
+ assertEquals(packageName, result.getCallingPackageName());
}
}
diff --git a/core/tests/coretests/src/android/view/textclassifier/TextLanguageTest.java b/core/tests/coretests/src/android/view/textclassifier/TextLanguageTest.java
index 75ca769..1dcaed6 100644
--- a/core/tests/coretests/src/android/view/textclassifier/TextLanguageTest.java
+++ b/core/tests/coretests/src/android/view/textclassifier/TextLanguageTest.java
@@ -69,10 +69,12 @@
final String bundleKey = "experiment.str";
final Bundle bundle = new Bundle();
bundle.putString(bundleKey, "bundle");
+ final String packageName = "packageName";
final TextLanguage.Request reference = new TextLanguage.Request.Builder(text)
.setExtras(bundle)
.build();
+ reference.setCallingPackageName(packageName);
final Parcel parcel = Parcel.obtain();
reference.writeToParcel(parcel, 0);
@@ -81,5 +83,6 @@
assertEquals(text, result.getText());
assertEquals("bundle", result.getExtras().getString(bundleKey));
+ assertEquals(packageName, result.getCallingPackageName());
}
}
diff --git a/core/tests/coretests/src/android/view/textclassifier/TextLinksTest.java b/core/tests/coretests/src/android/view/textclassifier/TextLinksTest.java
index f6ec0e6..f022d04 100644
--- a/core/tests/coretests/src/android/view/textclassifier/TextLinksTest.java
+++ b/core/tests/coretests/src/android/view/textclassifier/TextLinksTest.java
@@ -64,7 +64,7 @@
public void testParcel() {
final String fullText = "this is just a test";
final TextLinks reference = new TextLinks.Builder(fullText)
- .addLink(0, 4, getEntityScores(0.f, 0.f, 1.f))
+ .addLink(0, 4, getEntityScores(0.f, 0.f, 1.f), BUNDLE)
.addLink(5, 12, getEntityScores(.8f, .1f, .5f))
.setExtras(BUNDLE)
.build();
@@ -82,6 +82,7 @@
assertEquals(1, resultList.get(0).getEntityCount());
assertEquals(TextClassifier.TYPE_OTHER, resultList.get(0).getEntity(0));
assertEquals(1.f, resultList.get(0).getConfidenceScore(TextClassifier.TYPE_OTHER), 1e-7f);
+ assertEquals(BUNDLE_VALUE, resultList.get(0).getExtras().getString(BUNDLE_KEY));
assertEquals(5, resultList.get(1).getStart());
assertEquals(12, resultList.get(1).getEnd());
assertEquals(3, resultList.get(1).getEntityCount());
@@ -96,6 +97,7 @@
@Test
public void testParcelOptions() {
+ final String packageName = "packageName";
final TextClassifier.EntityConfig entityConfig = TextClassifier.EntityConfig.create(
Arrays.asList(TextClassifier.HINT_TEXT_IS_EDITABLE),
Arrays.asList("a", "b", "c"),
@@ -105,6 +107,7 @@
.setEntityConfig(entityConfig)
.setExtras(BUNDLE)
.build();
+ reference.setCallingPackageName(packageName);
// Parcel and unparcel.
final Parcel parcel = Parcel.obtain();
@@ -119,5 +122,6 @@
assertEquals(new HashSet<String>(Arrays.asList("a", "c")),
result.getEntityConfig().resolveEntityListModifications(Collections.emptyList()));
assertEquals(BUNDLE_VALUE, result.getExtras().getString(BUNDLE_KEY));
+ assertEquals(packageName, result.getCallingPackageName());
}
}
diff --git a/core/tests/coretests/src/android/view/textclassifier/TextSelectionTest.java b/core/tests/coretests/src/android/view/textclassifier/TextSelectionTest.java
index 7ea5108b..2ea49f7 100644
--- a/core/tests/coretests/src/android/view/textclassifier/TextSelectionTest.java
+++ b/core/tests/coretests/src/android/view/textclassifier/TextSelectionTest.java
@@ -75,11 +75,13 @@
@Test
public void testParcelRequest() {
final String text = "text";
+ final String packageName = "packageName";
final TextSelection.Request reference =
new TextSelection.Request.Builder(text, 0, text.length())
.setDefaultLocales(new LocaleList(Locale.US, Locale.GERMANY))
.setExtras(BUNDLE)
.build();
+ reference.setCallingPackageName(packageName);
// Parcel and unparcel.
final Parcel parcel = Parcel.obtain();
@@ -87,10 +89,11 @@
parcel.setDataPosition(0);
final TextSelection.Request result = TextSelection.Request.CREATOR.createFromParcel(parcel);
- assertEquals(text, result.getText());
+ assertEquals(text, result.getText().toString());
assertEquals(0, result.getStartIndex());
assertEquals(text.length(), result.getEndIndex());
assertEquals("en-US,de-DE", result.getDefaultLocales().toLanguageTags());
assertEquals(BUNDLE_VALUE, result.getExtras().getString(BUNDLE_KEY));
+ assertEquals(packageName, result.getCallingPackageName());
}
}
diff --git a/libs/hwui/Android.bp b/libs/hwui/Android.bp
index ed7d5e5..d22eaf3 100644
--- a/libs/hwui/Android.bp
+++ b/libs/hwui/Android.bp
@@ -178,6 +178,7 @@
"renderthread/CanvasContext.cpp",
"renderthread/DrawFrameTask.cpp",
"renderthread/EglManager.cpp",
+ "renderthread/ReliableSurface.cpp",
"renderthread/VulkanManager.cpp",
"renderthread/RenderProxy.cpp",
"renderthread/RenderTask.cpp",
diff --git a/libs/hwui/RecordingCanvas.cpp b/libs/hwui/RecordingCanvas.cpp
index c63e449..0b847af 100644
--- a/libs/hwui/RecordingCanvas.cpp
+++ b/libs/hwui/RecordingCanvas.cpp
@@ -912,18 +912,6 @@
fDL->drawAnnotation(rect, key, val);
}
-void RecordingCanvas::onDrawText(const void* text, size_t bytes, SkScalar x, SkScalar y,
- const SkPaint& paint) {
- fDL->drawText(text, bytes, x, y, paint);
-}
-void RecordingCanvas::onDrawPosText(const void* text, size_t bytes, const SkPoint pos[],
- const SkPaint& paint) {
- fDL->drawPosText(text, bytes, pos, paint);
-}
-void RecordingCanvas::onDrawPosTextH(const void* text, size_t bytes, const SkScalar xs[],
- SkScalar y, const SkPaint& paint) {
- fDL->drawPosTextH(text, bytes, xs, y, paint);
-}
void RecordingCanvas::onDrawTextRSXform(const void* text, size_t bytes, const SkRSXform xform[],
const SkRect* cull, const SkPaint& paint) {
fDL->drawTextRSXform(text, bytes, xform, cull, paint);
diff --git a/libs/hwui/RecordingCanvas.h b/libs/hwui/RecordingCanvas.h
index 08cfc62..35cf707 100644
--- a/libs/hwui/RecordingCanvas.h
+++ b/libs/hwui/RecordingCanvas.h
@@ -170,10 +170,6 @@
void onDrawPicture(const SkPicture*, const SkMatrix*, const SkPaint*) override;
void onDrawAnnotation(const SkRect&, const char[], SkData*) override;
- void onDrawText(const void*, size_t, SkScalar x, SkScalar y, const SkPaint&) override;
- void onDrawPosText(const void*, size_t, const SkPoint[], const SkPaint&) override;
- void onDrawPosTextH(const void*, size_t, const SkScalar[], SkScalar, const SkPaint&) override;
-
void onDrawTextRSXform(const void*, size_t, const SkRSXform[], const SkRect*,
const SkPaint&) override;
void onDrawTextBlob(const SkTextBlob*, SkScalar, SkScalar, const SkPaint&) override;
diff --git a/libs/hwui/pipeline/skia/DumpOpsCanvas.h b/libs/hwui/pipeline/skia/DumpOpsCanvas.h
index 2062194..2b5d580 100644
--- a/libs/hwui/pipeline/skia/DumpOpsCanvas.h
+++ b/libs/hwui/pipeline/skia/DumpOpsCanvas.h
@@ -82,18 +82,6 @@
mOutput << mIdent << "drawDRRect" << std::endl;
}
- void onDrawText(const void*, size_t, SkScalar, SkScalar, const SkPaint&) override {
- mOutput << mIdent << "drawText" << std::endl;
- }
-
- void onDrawPosText(const void*, size_t, const SkPoint[], const SkPaint&) override {
- mOutput << mIdent << "drawPosText" << std::endl;
- }
-
- void onDrawPosTextH(const void*, size_t, const SkScalar[], SkScalar, const SkPaint&) override {
- mOutput << mIdent << "drawPosTextH" << std::endl;
- }
-
void onDrawTextRSXform(const void*, size_t, const SkRSXform[], const SkRect*,
const SkPaint&) override {
mOutput << mIdent << "drawTextRSXform" << std::endl;
diff --git a/libs/hwui/pipeline/skia/SkiaOpenGLPipeline.cpp b/libs/hwui/pipeline/skia/SkiaOpenGLPipeline.cpp
index 142bca9..07979a2 100644
--- a/libs/hwui/pipeline/skia/SkiaOpenGLPipeline.cpp
+++ b/libs/hwui/pipeline/skia/SkiaOpenGLPipeline.cpp
@@ -155,7 +155,7 @@
}
}
-bool SkiaOpenGLPipeline::setSurface(Surface* surface, SwapBehavior swapBehavior,
+bool SkiaOpenGLPipeline::setSurface(ANativeWindow* surface, SwapBehavior swapBehavior,
ColorMode colorMode) {
if (mEglSurface != EGL_NO_SURFACE) {
mEglManager.destroySurface(mEglSurface);
diff --git a/libs/hwui/pipeline/skia/SkiaOpenGLPipeline.h b/libs/hwui/pipeline/skia/SkiaOpenGLPipeline.h
index 4ab3541..47991069 100644
--- a/libs/hwui/pipeline/skia/SkiaOpenGLPipeline.h
+++ b/libs/hwui/pipeline/skia/SkiaOpenGLPipeline.h
@@ -42,7 +42,7 @@
bool swapBuffers(const renderthread::Frame& frame, bool drew, const SkRect& screenDirty,
FrameInfo* currentFrameInfo, bool* requireSwap) override;
DeferredLayerUpdater* createTextureLayer() override;
- bool setSurface(Surface* window, renderthread::SwapBehavior swapBehavior,
+ bool setSurface(ANativeWindow* surface, renderthread::SwapBehavior swapBehavior,
renderthread::ColorMode colorMode) override;
void onStop() override;
bool isSurfaceReady() override;
diff --git a/libs/hwui/pipeline/skia/SkiaVulkanPipeline.cpp b/libs/hwui/pipeline/skia/SkiaVulkanPipeline.cpp
index 3607b23..437b5dc 100644
--- a/libs/hwui/pipeline/skia/SkiaVulkanPipeline.cpp
+++ b/libs/hwui/pipeline/skia/SkiaVulkanPipeline.cpp
@@ -115,7 +115,7 @@
void SkiaVulkanPipeline::onStop() {}
-bool SkiaVulkanPipeline::setSurface(Surface* surface, SwapBehavior swapBehavior,
+bool SkiaVulkanPipeline::setSurface(ANativeWindow* surface, SwapBehavior swapBehavior,
ColorMode colorMode) {
if (mVkSurface) {
mVkManager.destroySurface(mVkSurface);
diff --git a/libs/hwui/pipeline/skia/SkiaVulkanPipeline.h b/libs/hwui/pipeline/skia/SkiaVulkanPipeline.h
index 14c0d69..02874c7 100644
--- a/libs/hwui/pipeline/skia/SkiaVulkanPipeline.h
+++ b/libs/hwui/pipeline/skia/SkiaVulkanPipeline.h
@@ -38,7 +38,7 @@
bool swapBuffers(const renderthread::Frame& frame, bool drew, const SkRect& screenDirty,
FrameInfo* currentFrameInfo, bool* requireSwap) override;
DeferredLayerUpdater* createTextureLayer() override;
- bool setSurface(Surface* window, renderthread::SwapBehavior swapBehavior,
+ bool setSurface(ANativeWindow* surface, renderthread::SwapBehavior swapBehavior,
renderthread::ColorMode colorMode) override;
void onStop() override;
bool isSurfaceReady() override;
diff --git a/libs/hwui/renderthread/CanvasContext.cpp b/libs/hwui/renderthread/CanvasContext.cpp
index 6869972..4e4262c 100644
--- a/libs/hwui/renderthread/CanvasContext.cpp
+++ b/libs/hwui/renderthread/CanvasContext.cpp
@@ -142,7 +142,12 @@
void CanvasContext::setSurface(sp<Surface>&& surface) {
ATRACE_CALL();
- mNativeSurface = std::move(surface);
+ if (surface) {
+ mNativeSurface = new ReliableSurface{std::move(surface)};
+ mNativeSurface->setDequeueTimeout(500_ms);
+ } else {
+ mNativeSurface = nullptr;
+ }
ColorMode colorMode = mWideColorGamut ? ColorMode::WideColorGamut : ColorMode::SRGB;
bool hasSurface = mRenderPipeline->setSurface(mNativeSurface.get(), mSwapBehavior, colorMode);
@@ -285,10 +290,11 @@
info.damageAccumulator = &mDamageAccumulator;
info.layerUpdateQueue = &mLayerUpdateQueue;
+ info.out.canDrawThisFrame = true;
mAnimationContext->startFrame(info.mode);
mRenderPipeline->onPrepareTree();
- for (const sp<RenderNode>& node : mRenderNodes) {
+ for (const sp<RenderNode> &node : mRenderNodes) {
// Only the primary target node will be drawn full - all other nodes would get drawn in
// real time mode. In case of a window, the primary node is the window content and the other
// node(s) are non client / filler nodes.
@@ -304,7 +310,7 @@
mIsDirty = true;
- if (CC_UNLIKELY(!mNativeSurface.get())) {
+ if (CC_UNLIKELY(!hasSurface())) {
mCurrentFrameInfo->addFlag(FrameInfoFlags::SkippedFrame);
info.out.canDrawThisFrame = false;
return;
@@ -312,7 +318,7 @@
if (CC_LIKELY(mSwapHistory.size() && !Properties::forceDrawFrame)) {
nsecs_t latestVsync = mRenderThread.timeLord().latestVsync();
- SwapHistory& lastSwap = mSwapHistory.back();
+ SwapHistory &lastSwap = mSwapHistory.back();
nsecs_t vsyncDelta = std::abs(lastSwap.vsyncTime - latestVsync);
// The slight fudge-factor is to deal with cases where
// the vsync was estimated due to being slow handling the signal.
@@ -333,7 +339,19 @@
info.out.canDrawThisFrame = false;
}
- if (!info.out.canDrawThisFrame) {
+ if (info.out.canDrawThisFrame) {
+ int err = mNativeSurface->reserveNext();
+ if (err != OK) {
+ mCurrentFrameInfo->addFlag(FrameInfoFlags::SkippedFrame);
+ info.out.canDrawThisFrame = false;
+ ALOGW("reserveNext failed, error = %d (%s)", err, strerror(-err));
+ if (err != TIMED_OUT) {
+ // A timed out surface can still recover, but assume others are permanently dead.
+ setSurface(nullptr);
+ return;
+ }
+ }
+ } else {
mCurrentFrameInfo->addFlag(FrameInfoFlags::SkippedFrame);
}
diff --git a/libs/hwui/renderthread/CanvasContext.h b/libs/hwui/renderthread/CanvasContext.h
index 70be4a6..9e7abf4 100644
--- a/libs/hwui/renderthread/CanvasContext.h
+++ b/libs/hwui/renderthread/CanvasContext.h
@@ -25,6 +25,7 @@
#include "IRenderPipeline.h"
#include "LayerUpdateQueue.h"
#include "RenderNode.h"
+#include "ReliableSurface.h"
#include "renderthread/RenderTask.h"
#include "renderthread/RenderThread.h"
#include "thread/Task.h"
@@ -219,7 +220,7 @@
EGLint mLastFrameHeight = 0;
RenderThread& mRenderThread;
- sp<Surface> mNativeSurface;
+ sp<ReliableSurface> mNativeSurface;
// stopped indicates the CanvasContext will reject actual redraw operations,
// and defer repaint until it is un-stopped
bool mStopped = false;
diff --git a/libs/hwui/renderthread/EglManager.cpp b/libs/hwui/renderthread/EglManager.cpp
index 65ced6a..8230dfd 100644
--- a/libs/hwui/renderthread/EglManager.cpp
+++ b/libs/hwui/renderthread/EglManager.cpp
@@ -31,6 +31,8 @@
#include <string>
#include <vector>
+#include <system/window.h>
+#include <gui/Surface.h>
#define GLES_VERSION 2
@@ -106,7 +108,7 @@
LOG_ALWAYS_FATAL_IF(eglInitialize(mEglDisplay, &major, &minor) == EGL_FALSE,
"Failed to initialize display %p! err=%s", mEglDisplay, eglErrorString());
- ALOGI("Initialized EGL, version %d.%d", (int)major, (int)minor);
+ ALOGV("Initialized EGL, version %d.%d", (int)major, (int)minor);
initExtensions();
diff --git a/libs/hwui/renderthread/IRenderPipeline.h b/libs/hwui/renderthread/IRenderPipeline.h
index 4972554..42e17b273 100644
--- a/libs/hwui/renderthread/IRenderPipeline.h
+++ b/libs/hwui/renderthread/IRenderPipeline.h
@@ -28,9 +28,9 @@
class GrContext;
-namespace android {
+struct ANativeWindow;
-class Surface;
+namespace android {
namespace uirenderer {
@@ -67,7 +67,7 @@
virtual bool swapBuffers(const Frame& frame, bool drew, const SkRect& screenDirty,
FrameInfo* currentFrameInfo, bool* requireSwap) = 0;
virtual DeferredLayerUpdater* createTextureLayer() = 0;
- virtual bool setSurface(Surface* window, SwapBehavior swapBehavior, ColorMode colorMode) = 0;
+ virtual bool setSurface(ANativeWindow* window, SwapBehavior swapBehavior, ColorMode colorMode) = 0;
virtual void onStop() = 0;
virtual bool isSurfaceReady() = 0;
virtual bool isContextReady() = 0;
diff --git a/libs/hwui/renderthread/ReliableSurface.cpp b/libs/hwui/renderthread/ReliableSurface.cpp
new file mode 100644
index 0000000..6f2b9df
--- /dev/null
+++ b/libs/hwui/renderthread/ReliableSurface.cpp
@@ -0,0 +1,318 @@
+/*
+ * 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.
+ */
+
+#include "ReliableSurface.h"
+
+#include <private/android/AHardwareBufferHelpers.h>
+
+namespace android::uirenderer::renderthread {
+
+// TODO: Re-enable after addressing more of the TODO's
+// With this disabled we won't have a good up-front signal that the surface is no longer valid,
+// however we can at least handle that reactively post-draw. There's just not a good mechanism
+// to propagate this error back to the caller
+constexpr bool DISABLE_BUFFER_PREFETCH = true;
+
+// TODO: Make surface less protected
+// This exists because perform is a varargs, and ANativeWindow has no va_list perform.
+// So wrapping/chaining that is hard. Telling the compiler to ignore protected is easy, so we do
+// that instead
+struct SurfaceExposer : Surface {
+ // Make warnings happy
+ SurfaceExposer() = delete;
+
+ using Surface::setBufferCount;
+ using Surface::setSwapInterval;
+ using Surface::dequeueBuffer;
+ using Surface::queueBuffer;
+ using Surface::cancelBuffer;
+ using Surface::lockBuffer_DEPRECATED;
+ using Surface::perform;
+};
+
+#define callProtected(surface, func, ...) ((*surface).*&SurfaceExposer::func)(__VA_ARGS__)
+
+ReliableSurface::ReliableSurface(sp<Surface>&& surface) : mSurface(std::move(surface)) {
+ LOG_ALWAYS_FATAL_IF(!mSurface, "Error, unable to wrap a nullptr");
+
+ ANativeWindow::setSwapInterval = hook_setSwapInterval;
+ ANativeWindow::dequeueBuffer = hook_dequeueBuffer;
+ ANativeWindow::cancelBuffer = hook_cancelBuffer;
+ ANativeWindow::queueBuffer = hook_queueBuffer;
+ ANativeWindow::query = hook_query;
+ ANativeWindow::perform = hook_perform;
+
+ ANativeWindow::dequeueBuffer_DEPRECATED = hook_dequeueBuffer_DEPRECATED;
+ ANativeWindow::cancelBuffer_DEPRECATED = hook_cancelBuffer_DEPRECATED;
+ ANativeWindow::lockBuffer_DEPRECATED = hook_lockBuffer_DEPRECATED;
+ ANativeWindow::queueBuffer_DEPRECATED = hook_queueBuffer_DEPRECATED;
+}
+
+ReliableSurface::~ReliableSurface() {
+ clearReservedBuffer();
+}
+
+void ReliableSurface::perform(int operation, va_list args) {
+ std::lock_guard _lock{mMutex};
+
+ switch (operation) {
+ case NATIVE_WINDOW_SET_USAGE:
+ mUsage = va_arg(args, uint32_t);
+ break;
+ case NATIVE_WINDOW_SET_USAGE64:
+ mUsage = va_arg(args, uint64_t);
+ break;
+ case NATIVE_WINDOW_SET_BUFFERS_GEOMETRY:
+ /* width */ va_arg(args, uint32_t);
+ /* height */ va_arg(args, uint32_t);
+ mFormat = va_arg(args, PixelFormat);
+ break;
+ case NATIVE_WINDOW_SET_BUFFERS_FORMAT:
+ mFormat = va_arg(args, PixelFormat);
+ break;
+ }
+}
+
+int ReliableSurface::reserveNext() {
+ {
+ std::lock_guard _lock{mMutex};
+ if (mReservedBuffer) {
+ ALOGW("reserveNext called but there was already a buffer reserved?");
+ return OK;
+ }
+ if (mInErrorState) {
+ return UNKNOWN_ERROR;
+ }
+ if (mHasDequeuedBuffer) {
+ return OK;
+ }
+ if constexpr (DISABLE_BUFFER_PREFETCH) {
+ return OK;
+ }
+ }
+
+ // TODO: Update this to better handle when requested dimensions have changed
+ // Currently the driver does this via query + perform but that's after we've already
+ // reserved a buffer. Should we do that logic instead? Or should we drop
+ // the backing Surface to the ground and go full manual on the IGraphicBufferProducer instead?
+
+ int fenceFd = -1;
+ ANativeWindowBuffer* buffer = nullptr;
+ int result = callProtected(mSurface, dequeueBuffer, &buffer, &fenceFd);
+
+ {
+ std::lock_guard _lock{mMutex};
+ LOG_ALWAYS_FATAL_IF(mReservedBuffer, "race condition in reserveNext");
+ mReservedBuffer = buffer;
+ mReservedFenceFd.reset(fenceFd);
+ }
+
+ return result;
+}
+
+void ReliableSurface::clearReservedBuffer() {
+ ANativeWindowBuffer* buffer = nullptr;
+ int releaseFd = -1;
+ {
+ std::lock_guard _lock{mMutex};
+ if (mReservedBuffer) {
+ ALOGW("Reserved buffer %p was never used", mReservedBuffer);
+ buffer = mReservedBuffer;
+ releaseFd = mReservedFenceFd.release();
+ }
+ mReservedBuffer = nullptr;
+ mReservedFenceFd.reset();
+ mHasDequeuedBuffer = false;
+ }
+ if (buffer) {
+ callProtected(mSurface, cancelBuffer, buffer, releaseFd);
+ }
+}
+
+int ReliableSurface::cancelBuffer(ANativeWindowBuffer* buffer, int fenceFd) {
+ clearReservedBuffer();
+ if (isFallbackBuffer(buffer)) {
+ if (fenceFd > 0) {
+ close(fenceFd);
+ }
+ return OK;
+ }
+ int result = callProtected(mSurface, cancelBuffer, buffer, fenceFd);
+ return result;
+}
+
+int ReliableSurface::dequeueBuffer(ANativeWindowBuffer** buffer, int* fenceFd) {
+ {
+ std::lock_guard _lock{mMutex};
+ if (mReservedBuffer) {
+ *buffer = mReservedBuffer;
+ *fenceFd = mReservedFenceFd.release();
+ mReservedBuffer = nullptr;
+ return OK;
+ }
+ }
+
+ int result = callProtected(mSurface, dequeueBuffer, buffer, fenceFd);
+ if (result != OK) {
+ ALOGW("dequeueBuffer failed, error = %d; switching to fallback", result);
+ *buffer = acquireFallbackBuffer();
+ *fenceFd = -1;
+ return *buffer ? OK : INVALID_OPERATION;
+ } else {
+ std::lock_guard _lock{mMutex};
+ mHasDequeuedBuffer = true;
+ }
+ return OK;
+}
+
+int ReliableSurface::queueBuffer(ANativeWindowBuffer* buffer, int fenceFd) {
+ clearReservedBuffer();
+
+ if (isFallbackBuffer(buffer)) {
+ if (fenceFd > 0) {
+ close(fenceFd);
+ }
+ return OK;
+ }
+
+ int result = callProtected(mSurface, queueBuffer, buffer, fenceFd);
+ return result;
+}
+
+bool ReliableSurface::isFallbackBuffer(const ANativeWindowBuffer* windowBuffer) const {
+ if (!mScratchBuffer || !windowBuffer) {
+ return false;
+ }
+ ANativeWindowBuffer* scratchBuffer =
+ AHardwareBuffer_to_ANativeWindowBuffer(mScratchBuffer.get());
+ return windowBuffer == scratchBuffer;
+}
+
+ANativeWindowBuffer* ReliableSurface::acquireFallbackBuffer() {
+ std::lock_guard _lock{mMutex};
+ mInErrorState = true;
+
+ if (mScratchBuffer) {
+ return AHardwareBuffer_to_ANativeWindowBuffer(mScratchBuffer.get());
+ }
+
+ AHardwareBuffer_Desc desc;
+ desc.usage = mUsage;
+ desc.format = mFormat;
+ desc.width = 1;
+ desc.height = 1;
+ desc.layers = 1;
+ desc.rfu0 = 0;
+ desc.rfu1 = 0;
+ AHardwareBuffer* newBuffer = nullptr;
+ int err = AHardwareBuffer_allocate(&desc, &newBuffer);
+ if (err) {
+ // Allocate failed, that sucks
+ ALOGW("Failed to allocate scratch buffer, error=%d", err);
+ return nullptr;
+ }
+ mScratchBuffer.reset(newBuffer);
+ return AHardwareBuffer_to_ANativeWindowBuffer(newBuffer);
+}
+
+Surface* ReliableSurface::getWrapped(const ANativeWindow* window) {
+ return getSelf(window)->mSurface.get();
+}
+
+int ReliableSurface::hook_setSwapInterval(ANativeWindow* window, int interval) {
+ return callProtected(getWrapped(window), setSwapInterval, interval);
+}
+
+int ReliableSurface::hook_dequeueBuffer(ANativeWindow* window, ANativeWindowBuffer** buffer,
+ int* fenceFd) {
+ return getSelf(window)->dequeueBuffer(buffer, fenceFd);
+}
+
+int ReliableSurface::hook_cancelBuffer(ANativeWindow* window, ANativeWindowBuffer* buffer,
+ int fenceFd) {
+ return getSelf(window)->cancelBuffer(buffer, fenceFd);
+}
+
+int ReliableSurface::hook_queueBuffer(ANativeWindow* window, ANativeWindowBuffer* buffer,
+ int fenceFd) {
+ return getSelf(window)->queueBuffer(buffer, fenceFd);
+}
+
+int ReliableSurface::hook_dequeueBuffer_DEPRECATED(ANativeWindow* window,
+ ANativeWindowBuffer** buffer) {
+ ANativeWindowBuffer* buf;
+ int fenceFd = -1;
+ int result = window->dequeueBuffer(window, &buf, &fenceFd);
+ if (result != OK) {
+ return result;
+ }
+ sp<Fence> fence(new Fence(fenceFd));
+ int waitResult = fence->waitForever("dequeueBuffer_DEPRECATED");
+ if (waitResult != OK) {
+ ALOGE("dequeueBuffer_DEPRECATED: Fence::wait returned an error: %d", waitResult);
+ window->cancelBuffer(window, buf, -1);
+ return waitResult;
+ }
+ *buffer = buf;
+ return result;
+}
+
+int ReliableSurface::hook_cancelBuffer_DEPRECATED(ANativeWindow* window,
+ ANativeWindowBuffer* buffer) {
+ return window->cancelBuffer(window, buffer, -1);
+}
+
+int ReliableSurface::hook_lockBuffer_DEPRECATED(ANativeWindow* window,
+ ANativeWindowBuffer* buffer) {
+ // This method is a no-op in Surface as well
+ return OK;
+}
+
+int ReliableSurface::hook_queueBuffer_DEPRECATED(ANativeWindow* window,
+ ANativeWindowBuffer* buffer) {
+ return window->queueBuffer(window, buffer, -1);
+}
+
+int ReliableSurface::hook_query(const ANativeWindow* window, int what, int* value) {
+ return getWrapped(window)->query(what, value);
+}
+
+int ReliableSurface::hook_perform(ANativeWindow* window, int operation, ...) {
+ // Drop the reserved buffer if there is one since this (probably) mutated buffer dimensions
+ // TODO: Filter to things that only affect the reserved buffer
+ // TODO: Can we mutate the reserved buffer in some cases?
+ getSelf(window)->clearReservedBuffer();
+ va_list args;
+ va_start(args, operation);
+ int result = callProtected(getWrapped(window), perform, operation, args);
+ va_end(args);
+
+ switch (operation) {
+ case NATIVE_WINDOW_SET_BUFFERS_FORMAT:
+ case NATIVE_WINDOW_SET_USAGE:
+ case NATIVE_WINDOW_SET_USAGE64:
+ va_start(args, operation);
+ getSelf(window)->perform(operation, args);
+ va_end(args);
+ break;
+ default:
+ break;
+ }
+
+ return result;
+}
+
+}; // namespace android::uirenderer::renderthread
\ No newline at end of file
diff --git a/libs/hwui/renderthread/ReliableSurface.h b/libs/hwui/renderthread/ReliableSurface.h
new file mode 100644
index 0000000..0bfc72e
--- /dev/null
+++ b/libs/hwui/renderthread/ReliableSurface.h
@@ -0,0 +1,87 @@
+/*
+ * 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.
+ */
+
+#pragma once
+
+#include <gui/Surface.h>
+#include <utils/Macros.h>
+#include <utils/StrongPointer.h>
+
+#include <memory>
+
+namespace android::uirenderer::renderthread {
+
+class ReliableSurface : public ANativeObjectBase<ANativeWindow, ReliableSurface, RefBase> {
+ PREVENT_COPY_AND_ASSIGN(ReliableSurface);
+
+public:
+ ReliableSurface(sp<Surface>&& surface);
+ ~ReliableSurface();
+
+ void setDequeueTimeout(nsecs_t timeout) { mSurface->setDequeueTimeout(timeout); }
+
+ int reserveNext();
+
+ void allocateBuffers() { mSurface->allocateBuffers(); }
+
+ int query(int what, int* value) const { return mSurface->query(what, value); }
+
+ nsecs_t getLastDequeueStartTime() const { return mSurface->getLastDequeueStartTime(); }
+
+ uint64_t getNextFrameNumber() const { return mSurface->getNextFrameNumber(); }
+
+private:
+ const sp<Surface> mSurface;
+
+ mutable std::mutex mMutex;
+
+ uint64_t mUsage = AHARDWAREBUFFER_USAGE_GPU_FRAMEBUFFER;
+ PixelFormat mFormat = PIXEL_FORMAT_RGBA_8888;
+ std::unique_ptr<AHardwareBuffer, void (*)(AHardwareBuffer*)> mScratchBuffer{
+ nullptr, AHardwareBuffer_release};
+ ANativeWindowBuffer* mReservedBuffer = nullptr;
+ base::unique_fd mReservedFenceFd;
+ bool mHasDequeuedBuffer = false;
+ bool mInErrorState = false;
+
+ bool isFallbackBuffer(const ANativeWindowBuffer* windowBuffer) const;
+ ANativeWindowBuffer* acquireFallbackBuffer();
+ void clearReservedBuffer();
+
+ void perform(int operation, va_list args);
+ int cancelBuffer(ANativeWindowBuffer* buffer, int fenceFd);
+ int dequeueBuffer(ANativeWindowBuffer** buffer, int* fenceFd);
+ int queueBuffer(ANativeWindowBuffer* buffer, int fenceFd);
+
+ static Surface* getWrapped(const ANativeWindow*);
+
+ // ANativeWindow hooks
+ static int hook_cancelBuffer(ANativeWindow* window, ANativeWindowBuffer* buffer, int fenceFd);
+ static int hook_dequeueBuffer(ANativeWindow* window, ANativeWindowBuffer** buffer,
+ int* fenceFd);
+ static int hook_queueBuffer(ANativeWindow* window, ANativeWindowBuffer* buffer, int fenceFd);
+
+ static int hook_perform(ANativeWindow* window, int operation, ...);
+ static int hook_query(const ANativeWindow* window, int what, int* value);
+ static int hook_setSwapInterval(ANativeWindow* window, int interval);
+
+ static int hook_cancelBuffer_DEPRECATED(ANativeWindow* window, ANativeWindowBuffer* buffer);
+ static int hook_dequeueBuffer_DEPRECATED(ANativeWindow* window, ANativeWindowBuffer** buffer);
+ static int hook_lockBuffer_DEPRECATED(ANativeWindow* window, ANativeWindowBuffer* buffer);
+ static int hook_queueBuffer_DEPRECATED(ANativeWindow* window, ANativeWindowBuffer* buffer);
+};
+
+}; // namespace android::uirenderer::renderthread
\ No newline at end of file
diff --git a/libs/hwui/tests/unit/FatalTestCanvas.h b/libs/hwui/tests/unit/FatalTestCanvas.h
index 89f0c52..146662b 100644
--- a/libs/hwui/tests/unit/FatalTestCanvas.h
+++ b/libs/hwui/tests/unit/FatalTestCanvas.h
@@ -30,18 +30,6 @@
void onDrawDRRect(const SkRRect&, const SkRRect&, const SkPaint&) {
ADD_FAILURE() << "onDrawDRRect not expected in this test";
}
- void onDrawText(const void* text, size_t byteLength, SkScalar x, SkScalar y,
- const SkPaint& paint) {
- ADD_FAILURE() << "onDrawText not expected in this test";
- }
- void onDrawPosText(const void* text, size_t byteLength, const SkPoint pos[],
- const SkPaint& paint) {
- ADD_FAILURE() << "onDrawPosText not expected in this test";
- }
- void onDrawPosTextH(const void* text, size_t byteLength, const SkScalar xpos[], SkScalar constY,
- const SkPaint& paint) {
- ADD_FAILURE() << "onDrawPosTextH not expected in this test";
- }
void onDrawTextRSXform(const void* text, size_t byteLength, const SkRSXform[],
const SkRect* cullRect, const SkPaint& paint) {
ADD_FAILURE() << "onDrawTextRSXform not expected in this test";
diff --git a/location/java/android/location/ILocationManager.aidl b/location/java/android/location/ILocationManager.aidl
index ae87998..32c7520 100644
--- a/location/java/android/location/ILocationManager.aidl
+++ b/location/java/android/location/ILocationManager.aidl
@@ -96,9 +96,7 @@
void addTestProvider(String name, in ProviderProperties properties, String opPackageName);
void removeTestProvider(String provider, String opPackageName);
void setTestProviderLocation(String provider, in Location loc, String opPackageName);
- void clearTestProviderLocation(String provider, String opPackageName);
void setTestProviderEnabled(String provider, boolean enabled, String opPackageName);
- void clearTestProviderEnabled(String provider, String opPackageName);
// --- deprecated ---
void setTestProviderStatus(String provider, int status, in Bundle extras, long updateTime,
@@ -108,12 +106,8 @@
// --- internal ---
- // Used by location providers to tell the location manager when it has a new location.
- // Passive is true if the location is coming from the passive provider, in which case
- // it need not be shared with other providers.
+ // --- deprecated ---
void reportLocation(in Location location, boolean passive);
-
- // Used when a (initially Gnss) Location batch arrives
void reportLocationBatch(in List<Location> locations);
// for reporting callback completion
diff --git a/location/java/android/location/LocationManager.java b/location/java/android/location/LocationManager.java
index 3bf98b3..334170e 100644
--- a/location/java/android/location/LocationManager.java
+++ b/location/java/android/location/LocationManager.java
@@ -1537,14 +1537,11 @@
* mock location app op} is not set to {@link android.app.AppOpsManager#MODE_ALLOWED
* allowed} for your app.
* @throws IllegalArgumentException if no provider with the given name exists
+ *
+ * @deprecated This function has always been a no-op, and may be removed in the future.
*/
- public void clearTestProviderLocation(String provider) {
- try {
- mService.clearTestProviderLocation(provider, mContext.getOpPackageName());
- } catch (RemoteException e) {
- throw e.rethrowFromSystemServer();
- }
- }
+ @Deprecated
+ public void clearTestProviderLocation(String provider) {}
/**
* Sets a mock enabled value for the given provider. This value will be used in place
@@ -1575,13 +1572,12 @@
* mock location app op} is not set to {@link android.app.AppOpsManager#MODE_ALLOWED
* allowed} for your app.
* @throws IllegalArgumentException if no provider with the given name exists
+ *
+ * @deprecated Use {@link #setTestProviderEnabled(String, boolean)} instead.
*/
+ @Deprecated
public void clearTestProviderEnabled(String provider) {
- try {
- mService.clearTestProviderEnabled(provider, mContext.getOpPackageName());
- } catch (RemoteException e) {
- throw e.rethrowFromSystemServer();
- }
+ setTestProviderEnabled(provider, true);
}
/**
diff --git a/location/java/com/android/internal/location/ILocationProvider.aidl b/location/java/com/android/internal/location/ILocationProvider.aidl
index 39c2d92..71b54fb 100644
--- a/location/java/com/android/internal/location/ILocationProvider.aidl
+++ b/location/java/com/android/internal/location/ILocationProvider.aidl
@@ -16,29 +16,26 @@
package com.android.internal.location;
-import android.location.Location;
-import android.net.NetworkInfo;
import android.os.Bundle;
import android.os.WorkSource;
-import com.android.internal.location.ProviderProperties;
+import com.android.internal.location.ILocationProviderManager;
import com.android.internal.location.ProviderRequest;
/**
- * Binder interface for services that implement location providers.
- * <p>Use {@link LocationProviderBase} as a helper to implement this
- * interface.
+ * Binder interface for services that implement location providers. Do not implement this directly,
+ * extend {@link LocationProviderBase} instead.
* @hide
*/
interface ILocationProvider {
- void enable();
- void disable();
- void setRequest(in ProviderRequest request, in WorkSource ws);
+ oneway void setLocationProviderManager(in ILocationProviderManager manager);
- // --- deprecated (but still supported) ---
- ProviderProperties getProperties();
+ oneway void setRequest(in ProviderRequest request, in WorkSource ws);
+
+ oneway void sendExtraCommand(String command, in Bundle extras);
+
+ // --- deprecated and will be removed the future ---
int getStatus(out Bundle extras);
long getStatusUpdateTime();
- boolean sendExtraCommand(String command, inout Bundle extras);
}
diff --git a/location/java/android/location/IGnssStatusProvider.aidl b/location/java/com/android/internal/location/ILocationProviderManager.aidl
similarity index 61%
rename from location/java/android/location/IGnssStatusProvider.aidl
rename to location/java/com/android/internal/location/ILocationProviderManager.aidl
index 006b5d3..b1b8f0c 100644
--- a/location/java/android/location/IGnssStatusProvider.aidl
+++ b/location/java/com/android/internal/location/ILocationProviderManager.aidl
@@ -14,16 +14,21 @@
* limitations under the License.
*/
-package android.location;
+package com.android.internal.location;
-import android.location.IGnssStatusListener;
+import android.location.Location;
+
+import com.android.internal.location.ProviderProperties;
/**
- * An interface for location providers that provide GNSS status information.
- *
- * {@hide}
+ * Binder interface for manager of all location providers.
+ * @hide
*/
-interface IGnssStatusProvider {
- void registerGnssStatusCallback(IGnssStatusListener callback);
- void unregisterGnssStatusCallback(IGnssStatusListener callback);
+interface ILocationProviderManager {
+
+ void onSetEnabled(boolean enabled);
+
+ void onSetProperties(in ProviderProperties properties);
+
+ void onReportLocation(in Location location);
}
diff --git a/location/java/com/android/internal/location/ProviderRequest.java b/location/java/com/android/internal/location/ProviderRequest.java
index 88919f6..a45c20d 100644
--- a/location/java/com/android/internal/location/ProviderRequest.java
+++ b/location/java/com/android/internal/location/ProviderRequest.java
@@ -16,15 +16,15 @@
package com.android.internal.location;
-import java.util.ArrayList;
-import java.util.List;
-
import android.annotation.UnsupportedAppUsage;
import android.location.LocationRequest;
import android.os.Parcel;
import android.os.Parcelable;
import android.util.TimeUtils;
+import java.util.ArrayList;
+import java.util.List;
+
/** @hide */
public final class ProviderRequest implements Parcelable {
/** Location reporting is requested (true) */
@@ -36,6 +36,13 @@
public long interval = Long.MAX_VALUE;
/**
+ * When this flag is true, providers should ignore all location settings, user consents, power
+ * restrictions or any other restricting factors and always satisfy this request to the best of
+ * their ability. This flag should only be used in event of an emergency.
+ */
+ public boolean forceLocation = false;
+
+ /**
* Whether provider shall make stronger than normal tradeoffs to substantially restrict power
* use.
*/
diff --git a/location/lib/api/current.txt b/location/lib/api/current.txt
index d19559e..10c3447 100644
--- a/location/lib/api/current.txt
+++ b/location/lib/api/current.txt
@@ -8,14 +8,18 @@
public abstract class LocationProviderBase {
ctor public LocationProviderBase(java.lang.String, com.android.location.provider.ProviderPropertiesUnbundled);
method public android.os.IBinder getBinder();
- method public abstract void onDisable();
- method public void onDump(java.io.FileDescriptor, java.io.PrintWriter, java.lang.String[]);
- method public abstract void onEnable();
- method public deprecated int onGetStatus(android.os.Bundle);
- method public deprecated long onGetStatusUpdateTime();
- method public boolean onSendExtraCommand(java.lang.String, android.os.Bundle);
- method public abstract void onSetRequest(com.android.location.provider.ProviderRequestUnbundled, android.os.WorkSource);
- method public final void reportLocation(android.location.Location);
+ method public boolean isEnabled();
+ method protected deprecated void onDisable();
+ method protected void onDump(java.io.FileDescriptor, java.io.PrintWriter, java.lang.String[]);
+ method protected deprecated void onEnable();
+ method protected deprecated int onGetStatus(android.os.Bundle);
+ method protected deprecated long onGetStatusUpdateTime();
+ method protected void onInit();
+ method protected boolean onSendExtraCommand(java.lang.String, android.os.Bundle);
+ method protected abstract void onSetRequest(com.android.location.provider.ProviderRequestUnbundled, android.os.WorkSource);
+ method public void reportLocation(android.location.Location);
+ method public void setEnabled(boolean);
+ method public void setProperties(com.android.location.provider.ProviderPropertiesUnbundled);
field public static final java.lang.String EXTRA_NO_GPS_LOCATION = "noGPSLocation";
field public static final java.lang.String FUSED_PROVIDER = "fused";
}
@@ -38,6 +42,7 @@
}
public final class ProviderRequestUnbundled {
+ method public boolean getForceLocation();
method public long getInterval();
method public java.util.List<com.android.location.provider.LocationRequestUnbundled> getLocationRequests();
method public boolean getReportLocation();
diff --git a/location/lib/java/com/android/location/provider/LocationProviderBase.java b/location/lib/java/com/android/location/provider/LocationProviderBase.java
index d45a4ba..5bcec92 100644
--- a/location/lib/java/com/android/location/provider/LocationProviderBase.java
+++ b/location/lib/java/com/android/location/provider/LocationProviderBase.java
@@ -16,6 +16,7 @@
package com.android.location.provider;
+import android.annotation.Nullable;
import android.content.Context;
import android.location.ILocationManager;
import android.location.Location;
@@ -29,12 +30,11 @@
import android.util.Log;
import com.android.internal.location.ILocationProvider;
+import com.android.internal.location.ILocationProviderManager;
import com.android.internal.location.ProviderProperties;
import com.android.internal.location.ProviderRequest;
-import com.android.internal.util.FastPrintWriter;
import java.io.FileDescriptor;
-import java.io.FileOutputStream;
import java.io.PrintWriter;
/**
@@ -55,12 +55,6 @@
* of this package for more information.
*/
public abstract class LocationProviderBase {
- private final String TAG;
-
- /** @hide */
- protected final ILocationManager mLocationManager;
- private final ProviderProperties mProperties;
- private final IBinder mBinder;
/**
* Bundle key for a version of the location containing no GPS data.
@@ -77,49 +71,34 @@
*/
public static final String FUSED_PROVIDER = LocationManager.FUSED_PROVIDER;
- private final class Service extends ILocationProvider.Stub {
- @Override
- public void enable() {
- onEnable();
- }
- @Override
- public void disable() {
- onDisable();
- }
- @Override
- public void setRequest(ProviderRequest request, WorkSource ws) {
- onSetRequest(new ProviderRequestUnbundled(request), ws);
- }
- @Override
- public ProviderProperties getProperties() {
- return mProperties;
- }
- @Override
- public int getStatus(Bundle extras) {
- return onGetStatus(extras);
- }
- @Override
- public long getStatusUpdateTime() {
- return onGetStatusUpdateTime();
- }
- @Override
- public boolean sendExtraCommand(String command, Bundle extras) {
- return onSendExtraCommand(command, extras);
- }
- @Override
- public void dump(FileDescriptor fd, String[] args) {
- PrintWriter pw = new FastPrintWriter(new FileOutputStream(fd));
- onDump(fd, pw, args);
- pw.flush();
- }
- }
+ private final String mTag;
+ private final IBinder mBinder;
+
+ /**
+ * This field may be removed in the future, do not rely on it.
+ *
+ * @deprecated Do not use this field! Use LocationManager APIs instead. If you use this field
+ * you may be broken in the future.
+ * @hide
+ */
+ @Deprecated
+ protected final ILocationManager mLocationManager;
+
+ // write locked on mBinder, read lock is optional depending on atomicity requirements
+ @Nullable private volatile ILocationProviderManager mManager;
+ private volatile ProviderProperties mProperties;
+ private volatile boolean mEnabled;
public LocationProviderBase(String tag, ProviderPropertiesUnbundled properties) {
- TAG = tag;
- IBinder b = ServiceManager.getService(Context.LOCATION_SERVICE);
- mLocationManager = ILocationManager.Stub.asInterface(b);
- mProperties = properties.getProviderProperties();
+ mTag = tag;
mBinder = new Service();
+
+ mLocationManager = ILocationManager.Stub.asInterface(
+ ServiceManager.getService(Context.LOCATION_SERVICE));
+
+ mManager = null;
+ mProperties = properties.getProviderProperties();
+ mEnabled = true;
}
public IBinder getBinder() {
@@ -127,51 +106,116 @@
}
/**
- * Used by the location provider to report new locations.
+ * Sets whether this provider is currently enabled or not. Note that this is specific to the
+ * provider only, and is not related to global location settings. This is a hint to the Location
+ * Manager that this provider will generally be unable to fulfill incoming requests. This
+ * provider may still receive callbacks to onSetRequest while not enabled, and must decide
+ * whether to attempt to satisfy those requests or not.
*
- * @param location new Location to report
- *
- * Requires the android.permission.INSTALL_LOCATION_PROVIDER permission.
+ * Some guidelines: providers should set their own enabled/disabled status based only on state
+ * "owned" by that provider. For instance, providers should not take into account the state of
+ * the location master setting when setting themselves enabled or disabled, as this state is not
+ * owned by a particular provider. If a provider requires some additional user consent that is
+ * particular to the provider, this should be use to set the enabled/disabled state. If the
+ * provider proxies to another provider, the child provider's enabled/disabled state should be
+ * taken into account in the parent's enabled/disabled state. For most providers, it is expected
+ * that they will be always enabled.
*/
- public final void reportLocation(Location location) {
- try {
- mLocationManager.reportLocation(location, false);
- } catch (RemoteException e) {
- Log.e(TAG, "RemoteException", e);
- } catch (Exception e) {
- // never crash provider, might be running in a system process
- Log.e(TAG, "Exception", e);
+ public void setEnabled(boolean enabled) {
+ synchronized (mBinder) {
+ if (mEnabled == enabled) {
+ return;
+ }
+
+ mEnabled = enabled;
+ }
+
+ ILocationProviderManager manager = mManager;
+ if (manager != null) {
+ try {
+ manager.onSetEnabled(mEnabled);
+ } catch (RemoteException | RuntimeException e) {
+ Log.w(mTag, e);
+ }
}
}
/**
- * Enable the location provider.
- * <p>The provider may initialize resources, but does
- * not yet need to report locations.
+ * Sets the provider properties that may be queried by clients. Generally speaking, providers
+ * should try to avoid changing their properties after construction.
*/
- public abstract void onEnable();
+ public void setProperties(ProviderPropertiesUnbundled properties) {
+ synchronized (mBinder) {
+ mProperties = properties.getProviderProperties();
+ }
+
+ ILocationProviderManager manager = mManager;
+ if (manager != null) {
+ try {
+ manager.onSetProperties(mProperties);
+ } catch (RemoteException | RuntimeException e) {
+ Log.w(mTag, e);
+ }
+ }
+ }
/**
- * Disable the location provider.
- * <p>The provider must release resources, and stop
- * performing work. It may no longer report locations.
+ * Returns true if this provider has been set as enabled. This will be true unless explicitly
+ * set otherwise.
*/
- public abstract void onDisable();
+ public boolean isEnabled() {
+ return mEnabled;
+ }
/**
- * Set the {@link ProviderRequest} requirements for this provider.
- * <p>Each call to this method overrides all previous requests.
- * <p>This method might trigger the provider to start returning
- * locations, or to stop returning locations, depending on the
- * parameters in the request.
+ * Reports a new location from this provider.
*/
- public abstract void onSetRequest(ProviderRequestUnbundled request, WorkSource source);
+ public void reportLocation(Location location) {
+ ILocationProviderManager manager = mManager;
+ if (manager != null) {
+ try {
+ manager.onReportLocation(location);
+ } catch (RemoteException | RuntimeException e) {
+ Log.w(mTag, e);
+ }
+ }
+ }
+
+ protected void onInit() {
+ // call once so that providers designed for APIs pre-Q are not broken
+ onEnable();
+ }
+
+ /**
+ * @deprecated This callback will be invoked once when the provider is created to maintain
+ * backwards compatibility with providers not designed for Android Q and above. This method
+ * should only be implemented in location providers that need to support SDKs below Android Q.
+ * Even in this case, it is usually unnecessary to implement this callback with the correct
+ * design. This method may be removed in the future.
+ */
+ @Deprecated
+ protected void onEnable() {}
+
+ /**
+ * @deprecated This callback will be never be invoked on Android Q and above. This method should
+ * only be implemented in location providers that need to support SDKs below Android Q. Even in
+ * this case, it is usually unnecessary to implement this callback with the correct design. This
+ * method may be removed in the future.
+ */
+ @Deprecated
+ protected void onDisable() {}
+
+ /**
+ * Set the {@link ProviderRequest} requirements for this provider. Each call to this method
+ * overrides all previous requests. This method might trigger the provider to start returning
+ * locations, or to stop returning locations, depending on the parameters in the request.
+ */
+ protected abstract void onSetRequest(ProviderRequestUnbundled request, WorkSource source);
/**
* Dump debug information.
*/
- public void onDump(FileDescriptor fd, PrintWriter pw, String[] args) {
- }
+ protected void onDump(FileDescriptor fd, PrintWriter pw, String[] args) {}
/**
* This method will no longer be invoked.
@@ -187,10 +231,12 @@
* <p>If extras is non-null, additional status information may be
* added to it in the form of provider-specific key/value pairs.
*
- * @deprecated This method will no longer be invoked.
+ * @deprecated This callback will be never be invoked on Android Q and above. This method should
+ * only be implemented in location providers that need to support SDKs below Android Q. This
+ * method may be removed in the future.
*/
@Deprecated
- public int onGetStatus(Bundle extras) {
+ protected int onGetStatus(Bundle extras) {
return LocationProvider.AVAILABLE;
}
@@ -206,24 +252,64 @@
*
* @return time of last status update in millis since last reboot
*
- * @deprecated This method will no longer be invoked.
+ * @deprecated This callback will be never be invoked on Android Q and above. This method should
+ * only be implemented in location providers that need to support SDKs below Android Q. This
+ * method may be removed in the future.
*/
@Deprecated
- public long onGetStatusUpdateTime() {
+ protected long onGetStatusUpdateTime() {
return 0;
}
/**
- * Implements addditional location provider specific additional commands.
- *
- * @param command name of the command to send to the provider.
- * @param extras optional arguments for the command (or null).
- * The provider may optionally fill the extras Bundle with results from the command.
- *
- * @return true if the command succeeds.
+ * Implements location provider specific custom commands. The return value will be ignored on
+ * Android Q and above.
*/
- public boolean onSendExtraCommand(String command, Bundle extras) {
- // default implementation
+ protected boolean onSendExtraCommand(@Nullable String command, @Nullable Bundle extras) {
return false;
}
+
+ private final class Service extends ILocationProvider.Stub {
+
+ @Override
+ public void setLocationProviderManager(ILocationProviderManager manager) {
+ synchronized (mBinder) {
+ try {
+ manager.onSetProperties(mProperties);
+ manager.onSetEnabled(mEnabled);
+ } catch (RemoteException e) {
+ Log.w(mTag, e);
+ }
+
+ mManager = manager;
+ }
+
+ onInit();
+ }
+
+ @Override
+ public void setRequest(ProviderRequest request, WorkSource ws) {
+ onSetRequest(new ProviderRequestUnbundled(request), ws);
+ }
+
+ @Override
+ public int getStatus(Bundle extras) {
+ return onGetStatus(extras);
+ }
+
+ @Override
+ public long getStatusUpdateTime() {
+ return onGetStatusUpdateTime();
+ }
+
+ @Override
+ public void sendExtraCommand(String command, Bundle extras) {
+ onSendExtraCommand(command, extras);
+ }
+
+ @Override
+ public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
+ onDump(fd, pw, args);
+ }
+ }
}
diff --git a/location/lib/java/com/android/location/provider/ProviderRequestUnbundled.java b/location/lib/java/com/android/location/provider/ProviderRequestUnbundled.java
index 6a8e618..b825b58 100644
--- a/location/lib/java/com/android/location/provider/ProviderRequestUnbundled.java
+++ b/location/lib/java/com/android/location/provider/ProviderRequestUnbundled.java
@@ -16,13 +16,13 @@
package com.android.location.provider;
-import java.util.ArrayList;
-import java.util.List;
-
import android.location.LocationRequest;
import com.android.internal.location.ProviderRequest;
+import java.util.ArrayList;
+import java.util.List;
+
/**
* This class is an interface to Provider Requests for unbundled applications.
*
@@ -46,6 +46,10 @@
return mRequest.interval;
}
+ public boolean getForceLocation() {
+ return mRequest.forceLocation;
+ }
+
/**
* Never null.
*/
diff --git a/media/java/android/media/AudioFormat.java b/media/java/android/media/AudioFormat.java
index 3e3e651..793aa27 100644
--- a/media/java/android/media/AudioFormat.java
+++ b/media/java/android/media/AudioFormat.java
@@ -213,6 +213,8 @@
* (e.g.{@link AudioTrack#getPlaybackHeadPosition()
* AudioTrack.getPlaybackHeadPosition()}),
* depending on the context where audio frame is used.
+ * For the purposes of {@link AudioFormat#getFrameSizeInBytes()}, a compressed data format
+ * returns a frame size of 1 byte.
*/
public final class AudioFormat implements Parcelable {
@@ -670,27 +672,53 @@
}
/**
- * Private constructor with an ignored argument to differentiate from the removed default ctor
- * @param ignoredArgument
- */
- private AudioFormat(int ignoredArgument) {
- }
-
- /**
* Constructor used by the JNI. Parameters are not checked for validity.
*/
// Update sound trigger JNI in core/jni/android_hardware_SoundTrigger.cpp when modifying this
// constructor
@UnsupportedAppUsage
private AudioFormat(int encoding, int sampleRate, int channelMask, int channelIndexMask) {
- mEncoding = encoding;
- mSampleRate = sampleRate;
- mChannelMask = channelMask;
- mChannelIndexMask = channelIndexMask;
- mPropertySetMask = AUDIO_FORMAT_HAS_PROPERTY_ENCODING |
- AUDIO_FORMAT_HAS_PROPERTY_SAMPLE_RATE |
- AUDIO_FORMAT_HAS_PROPERTY_CHANNEL_MASK |
- AUDIO_FORMAT_HAS_PROPERTY_CHANNEL_INDEX_MASK;
+ this(
+ AUDIO_FORMAT_HAS_PROPERTY_ENCODING
+ | AUDIO_FORMAT_HAS_PROPERTY_SAMPLE_RATE
+ | AUDIO_FORMAT_HAS_PROPERTY_CHANNEL_MASK
+ | AUDIO_FORMAT_HAS_PROPERTY_CHANNEL_INDEX_MASK,
+ encoding, sampleRate, channelMask, channelIndexMask
+ );
+ }
+
+ private AudioFormat(int propertySetMask,
+ int encoding, int sampleRate, int channelMask, int channelIndexMask) {
+ mPropertySetMask = propertySetMask;
+ mEncoding = (propertySetMask & AUDIO_FORMAT_HAS_PROPERTY_ENCODING) != 0
+ ? encoding : ENCODING_INVALID;
+ mSampleRate = (propertySetMask & AUDIO_FORMAT_HAS_PROPERTY_SAMPLE_RATE) != 0
+ ? sampleRate : SAMPLE_RATE_UNSPECIFIED;
+ mChannelMask = (propertySetMask & AUDIO_FORMAT_HAS_PROPERTY_CHANNEL_MASK) != 0
+ ? channelMask : CHANNEL_INVALID;
+ mChannelIndexMask = (propertySetMask & AUDIO_FORMAT_HAS_PROPERTY_CHANNEL_INDEX_MASK) != 0
+ ? channelIndexMask : CHANNEL_INVALID;
+
+ // Compute derived values.
+
+ final int channelIndexCount = Integer.bitCount(getChannelIndexMask());
+ int channelCount = channelCountFromOutChannelMask(getChannelMask());
+ if (channelCount == 0) {
+ channelCount = channelIndexCount;
+ } else if (channelCount != channelIndexCount && channelIndexCount != 0) {
+ channelCount = 0; // position and index channel count mismatch
+ }
+ mChannelCount = channelCount;
+
+ int frameSizeInBytes = 1;
+ try {
+ frameSizeInBytes = getBytesPerSample(mEncoding) * channelCount;
+ } catch (IllegalArgumentException iae) {
+ // ignored
+ }
+ // it is possible that channel count is 0, so ensure we return 1 for
+ // mFrameSizeInBytes for consistency.
+ mFrameSizeInBytes = frameSizeInBytes != 0 ? frameSizeInBytes : 1;
}
/** @hide */
@@ -704,14 +732,21 @@
/** @hide */
public final static int AUDIO_FORMAT_HAS_PROPERTY_CHANNEL_INDEX_MASK = 0x1 << 3;
+ // This is an immutable class, all member variables are final.
+
+ // Essential values.
@UnsupportedAppUsage
- private int mEncoding;
+ private final int mEncoding;
@UnsupportedAppUsage
- private int mSampleRate;
+ private final int mSampleRate;
@UnsupportedAppUsage
- private int mChannelMask;
- private int mChannelIndexMask;
- private int mPropertySetMask;
+ private final int mChannelMask;
+ private final int mChannelIndexMask;
+ private final int mPropertySetMask;
+
+ // Derived values computed in the constructor, cached here.
+ private final int mChannelCount;
+ private final int mFrameSizeInBytes;
/**
* Return the encoding.
@@ -721,9 +756,6 @@
* {@link AudioFormat#ENCODING_INVALID} if not set.
*/
public int getEncoding() {
- if ((mPropertySetMask & AUDIO_FORMAT_HAS_PROPERTY_ENCODING) == 0) {
- return ENCODING_INVALID;
- }
return mEncoding;
}
@@ -745,9 +777,6 @@
* {@link AudioFormat#CHANNEL_INVALID} if not set.
*/
public int getChannelMask() {
- if ((mPropertySetMask & AUDIO_FORMAT_HAS_PROPERTY_CHANNEL_MASK) == 0) {
- return CHANNEL_INVALID;
- }
return mChannelMask;
}
@@ -760,9 +789,6 @@
* {@link AudioFormat#CHANNEL_INVALID} if not set or an invalid mask was used.
*/
public int getChannelIndexMask() {
- if ((mPropertySetMask & AUDIO_FORMAT_HAS_PROPERTY_CHANNEL_INDEX_MASK) == 0) {
- return CHANNEL_INVALID;
- }
return mChannelIndexMask;
}
@@ -772,14 +798,26 @@
* Zero is returned if both the channel position mask and the channel index mask are not set.
*/
public int getChannelCount() {
- final int channelIndexCount = Integer.bitCount(getChannelIndexMask());
- int channelCount = channelCountFromOutChannelMask(getChannelMask());
- if (channelCount == 0) {
- channelCount = channelIndexCount;
- } else if (channelCount != channelIndexCount && channelIndexCount != 0) {
- channelCount = 0; // position and index channel count mismatch
- }
- return channelCount;
+ return mChannelCount;
+ }
+
+ /**
+ * Return the frame size in bytes.
+ *
+ * For PCM or PCM packed compressed data this is the size of a sample multiplied
+ * by the channel count. For all other cases, including invalid/unset channel masks,
+ * this will return 1 byte.
+ * As an example, a stereo 16-bit PCM format would have a frame size of 4 bytes,
+ * an 8 channel float PCM format would have a frame size of 32 bytes,
+ * and a compressed data format (not packed in PCM) would have a frame size of 1 byte.
+ *
+ * Both {@link AudioRecord} or {@link AudioTrack} process data in multiples of
+ * this frame size.
+ *
+ * @return The audio frame size in bytes corresponding to the encoding and the channel mask.
+ */
+ public int getFrameSizeInBytes() {
+ return mFrameSizeInBytes;
}
/** @hide */
@@ -790,7 +828,7 @@
/** @hide */
public String toLogFriendlyString() {
return String.format("%dch %dHz %s",
- getChannelCount(), mSampleRate, toLogFriendlyEncoding(mEncoding));
+ mChannelCount, mSampleRate, toLogFriendlyEncoding(mEncoding));
}
/**
@@ -839,14 +877,13 @@
* @return a new {@link AudioFormat} object
*/
public AudioFormat build() {
- AudioFormat af = new AudioFormat(1980/*ignored*/);
- af.mEncoding = mEncoding;
- // not calling setSampleRate is equivalent to calling
- // setSampleRate(SAMPLE_RATE_UNSPECIFIED)
- af.mSampleRate = mSampleRate;
- af.mChannelMask = mChannelMask;
- af.mChannelIndexMask = mChannelIndexMask;
- af.mPropertySetMask = mPropertySetMask;
+ AudioFormat af = new AudioFormat(
+ mPropertySetMask,
+ mEncoding,
+ mSampleRate,
+ mChannelMask,
+ mChannelIndexMask
+ );
return af;
}
@@ -1049,11 +1086,13 @@
}
private AudioFormat(Parcel in) {
- mPropertySetMask = in.readInt();
- mEncoding = in.readInt();
- mSampleRate = in.readInt();
- mChannelMask = in.readInt();
- mChannelIndexMask = in.readInt();
+ this(
+ in.readInt(), // propertySetMask
+ in.readInt(), // encoding
+ in.readInt(), // sampleRate
+ in.readInt(), // channelMask
+ in.readInt() // channelIndexMask
+ );
}
public static final Parcelable.Creator<AudioFormat> CREATOR =
diff --git a/media/java/android/media/AudioTrack.java b/media/java/android/media/AudioTrack.java
index 2c4ec3a..e4d4795 100644
--- a/media/java/android/media/AudioTrack.java
+++ b/media/java/android/media/AudioTrack.java
@@ -3365,7 +3365,7 @@
int offsetInFloats, int sizeInFloats, int format,
boolean isBlocking);
- private native final int native_write_native_bytes(Object audioData,
+ private native final int native_write_native_bytes(ByteBuffer audioData,
int positionInBytes, int sizeInBytes, int format, boolean blocking);
private native final int native_reload_static();
diff --git a/media/java/android/media/MediaCodec.java b/media/java/android/media/MediaCodec.java
index 1d27c03..242ae46 100644
--- a/media/java/android/media/MediaCodec.java
+++ b/media/java/android/media/MediaCodec.java
@@ -3308,6 +3308,55 @@
public static final String PARAMETER_KEY_REQUEST_SYNC_FRAME = "request-sync";
/**
+ * Set the HDR10+ metadata on the next queued input frame.
+ *
+ * Provide a byte array of data that's conforming to the
+ * user_data_registered_itu_t_t35() syntax of SEI message for ST 2094-40.
+ *<p>
+ * For decoders:
+ *<p>
+ * When a decoder is configured for one of the HDR10+ profiles that uses
+ * out-of-band metadata (such as {@link
+ * MediaCodecInfo.CodecProfileLevel#VP9Profile2HDR10Plus} or {@link
+ * MediaCodecInfo.CodecProfileLevel#VP9Profile3HDR10Plus}), this
+ * parameter sets the HDR10+ metadata on the next input buffer queued
+ * to the decoder. A decoder supporting these profiles must propagate
+ * the metadata to the format of the output buffer corresponding to this
+ * particular input buffer (under key {@link MediaFormat#KEY_HDR10_PLUS_INFO}).
+ * The metadata should be applied to that output buffer and the buffers
+ * following it (in display order), until the next output buffer (in
+ * display order) upon which an HDR10+ metadata is set.
+ *<p>
+ * This parameter shouldn't be set if the decoder is not configured for
+ * an HDR10+ profile that uses out-of-band metadata. In particular,
+ * it shouldn't be set for HDR10+ profiles that uses in-band metadata
+ * where the metadata is embedded in the input buffers, for example
+ * {@link MediaCodecInfo.CodecProfileLevel#HEVCProfileMain10HDR10Plus}.
+ *<p>
+ * For encoders:
+ *<p>
+ * When an encoder is configured for one of the HDR10+ profiles and the
+ * operates in byte buffer input mode (instead of surface input mode),
+ * this parameter sets the HDR10+ metadata on the next input buffer queued
+ * to the encoder. For the HDR10+ profiles that uses out-of-band metadata
+ * (such as {@link MediaCodecInfo.CodecProfileLevel#VP9Profile2HDR10Plus},
+ * or {@link MediaCodecInfo.CodecProfileLevel#VP9Profile3HDR10Plus}),
+ * the metadata must be propagated to the format of the output buffer
+ * corresponding to this particular input buffer (under key {@link
+ * MediaFormat#KEY_HDR10_PLUS_INFO}). For the HDR10+ profiles that uses
+ * in-band metadata (such as {@link
+ * MediaCodecInfo.CodecProfileLevel#HEVCProfileMain10HDR10Plus}), the
+ * metadata info must be embedded in the corresponding output buffer itself.
+ *<p>
+ * This parameter shouldn't be set if the encoder is not configured for
+ * an HDR10+ profile, or if it's operating in surface input mode.
+ *<p>
+ *
+ * @see MediaFormat#KEY_HDR10_PLUS_INFO
+ */
+ public static final String PARAMETER_KEY_HDR10_PLUS_INFO = MediaFormat.KEY_HDR10_PLUS_INFO;
+
+ /**
* Communicate additional parameter changes to the component instance.
* <b>Note:</b> Some of these parameter changes may silently fail to apply.
*
@@ -3325,7 +3374,14 @@
int i = 0;
for (final String key: params.keySet()) {
keys[i] = key;
- values[i] = params.get(key);
+ Object value = params.get(key);
+
+ // Bundle's byte array is a byte[], JNI layer only takes ByteBuffer
+ if (value instanceof byte[]) {
+ values[i] = ByteBuffer.wrap((byte[])value);
+ } else {
+ values[i] = value;
+ }
++i;
}
diff --git a/media/java/android/media/MediaCodecInfo.java b/media/java/android/media/MediaCodecInfo.java
index 6301993..95e3df2 100644
--- a/media/java/android/media/MediaCodecInfo.java
+++ b/media/java/android/media/MediaCodecInfo.java
@@ -2516,6 +2516,8 @@
case CodecProfileLevel.VP9Profile3:
case CodecProfileLevel.VP9Profile2HDR:
case CodecProfileLevel.VP9Profile3HDR:
+ case CodecProfileLevel.VP9Profile2HDR10Plus:
+ case CodecProfileLevel.VP9Profile3HDR10Plus:
break;
default:
Log.w(TAG, "Unrecognized profile "
@@ -2608,7 +2610,9 @@
switch (profileLevel.profile) {
case CodecProfileLevel.HEVCProfileMain:
case CodecProfileLevel.HEVCProfileMain10:
+ case CodecProfileLevel.HEVCProfileMainStill:
case CodecProfileLevel.HEVCProfileMain10HDR10:
+ case CodecProfileLevel.HEVCProfileMain10HDR10Plus:
break;
default:
Log.w(TAG, "Unrecognized profile "
@@ -2999,6 +3003,8 @@
// HDR profiles also support passing HDR metadata
public static final int VP9Profile2HDR = 0x1000;
public static final int VP9Profile3HDR = 0x2000;
+ public static final int VP9Profile2HDR10Plus = 0x4000;
+ public static final int VP9Profile3HDR10Plus = 0x8000;
// from OMX_VIDEO_VP9LEVELTYPE
public static final int VP9Level1 = 0x1;
@@ -3021,6 +3027,7 @@
public static final int HEVCProfileMain10 = 0x02;
public static final int HEVCProfileMainStill = 0x04;
public static final int HEVCProfileMain10HDR10 = 0x1000;
+ public static final int HEVCProfileMain10HDR10Plus = 0x2000;
// from OMX_VIDEO_HEVCLEVELTYPE
public static final int HEVCMainTierLevel1 = 0x1;
diff --git a/media/java/android/media/MediaFormat.java b/media/java/android/media/MediaFormat.java
index b7743c9..b62108f 100644
--- a/media/java/android/media/MediaFormat.java
+++ b/media/java/android/media/MediaFormat.java
@@ -910,6 +910,27 @@
public static final String KEY_HDR_STATIC_INFO = "hdr-static-info";
/**
+ * An optional key describing the HDR10+ metadata of the video content.
+ *
+ * The associated value is a ByteBuffer containing HDR10+ metadata conforming to the
+ * user_data_registered_itu_t_t35() syntax of SEI message for ST 2094-40. This key will
+ * be present on:
+ *<p>
+ * - The formats of output buffers of a decoder configured for HDR10+ profiles (such as
+ * {@link MediaCodecInfo.CodecProfileLevel#VP9Profile2HDR10Plus}, {@link
+ * MediaCodecInfo.CodecProfileLevel#VP9Profile3HDR10Plus} or {@link
+ * MediaCodecInfo.CodecProfileLevel#HEVCProfileMain10HDR10Plus}), or
+ *<p>
+ * - The formats of output buffers of an encoder configured for an HDR10+ profiles that
+ * uses out-of-band metadata (such as {@link
+ * MediaCodecInfo.CodecProfileLevel#VP9Profile2HDR10Plus} or {@link
+ * MediaCodecInfo.CodecProfileLevel#VP9Profile3HDR10Plus}).
+ *
+ * @see MediaCodec#PARAMETER_KEY_HDR10_PLUS_INFO
+ */
+ public static final String KEY_HDR10_PLUS_INFO = "hdr10-plus-info";
+
+ /**
* A key describing a unique ID for the content of a media track.
*
* <p>This key is used by {@link MediaExtractor}. Some extractors provide multiple encodings
diff --git a/media/java/android/media/MediaPlayer2.java b/media/java/android/media/MediaPlayer2.java
index 4805780..9038f72 100644
--- a/media/java/android/media/MediaPlayer2.java
+++ b/media/java/android/media/MediaPlayer2.java
@@ -1711,10 +1711,12 @@
public MediaTimestamp getTimestamp() {
try {
// TODO: get the timestamp from native side
- return new MediaTimestamp(
- getCurrentPosition() * 1000L,
- System.nanoTime(),
- getState() == PLAYER_STATE_PLAYING ? getPlaybackParams().getSpeed() : 0.f);
+ return new MediaTimestamp.Builder()
+ .setMediaTimestamp(
+ getCurrentPosition() * 1000L,
+ System.nanoTime(),
+ getState() == PLAYER_STATE_PLAYING ? getPlaybackParams().getSpeed() : 0.f)
+ .build();
} catch (IllegalStateException e) {
return null;
}
@@ -2398,11 +2400,13 @@
return;
}
Iterator<Value> in = playerMsg.getValuesList().iterator();
- SubtitleData data = new SubtitleData(
- in.next().getInt32Value(), // trackIndex
- in.next().getInt64Value(), // startTimeUs
- in.next().getInt64Value(), // durationUs
- in.next().getBytesValue().toByteArray()); // data
+ SubtitleData data = new SubtitleData.Builder()
+ .setSubtitleData(
+ in.next().getInt32Value(), // trackIndex
+ in.next().getInt64Value(), // startTimeUs
+ in.next().getInt64Value(), // durationUs
+ in.next().getBytesValue().toByteArray()) // data
+ .build();
sendEvent(new EventNotifier() {
@Override
public void notify(EventCallback callback) {
@@ -2426,9 +2430,11 @@
return;
}
Iterator<Value> in = playerMsg.getValuesList().iterator();
- data = new TimedMetaData(
- in.next().getInt64Value(), // timestampUs
- in.next().getBytesValue().toByteArray()); // metaData
+ data = new TimedMetaData.Builder()
+ .setTimedMetaData(
+ in.next().getInt64Value(), // timestampUs
+ in.next().getBytesValue().toByteArray()) // metaData
+ .build();
} else {
data = null;
}
diff --git a/media/java/android/media/MediaTimestamp.java b/media/java/android/media/MediaTimestamp.java
index e079a8e..03e454c 100644
--- a/media/java/android/media/MediaTimestamp.java
+++ b/media/java/android/media/MediaTimestamp.java
@@ -16,6 +16,9 @@
package android.media;
+import android.annotation.NonNull;
+import android.annotation.SystemApi;
+
/**
* An immutable object that represents the linear correlation between the media time
* and the system time. It contains the media clock rate, together with the media timestamp
@@ -117,4 +120,71 @@
+ " clockRate=" + clockRate
+ "}";
}
+
+ /**
+ * Builder class for {@link MediaTimestamp} objects.
+ * <p> Here is an example where <code>Builder</code> is used to define the
+ * {@link MediaTimestamp}:
+ *
+ * <pre class="prettyprint">
+ * MediaTimestamp mts = new MediaTimestamp.Builder()
+ * .setMediaTimestamp(mediaTime, systemTime, rate)
+ * .build();
+ * </pre>
+ * @hide
+ */
+ @SystemApi
+ public static class Builder {
+ long mMediaTimeUs;
+ long mNanoTime;
+ float mClockRate = 1.0f;
+
+ /**
+ * Constructs a new Builder with the defaults.
+ */
+ public Builder() {
+ }
+
+ /**
+ * Constructs a new Builder from a given {@link MediaTimestamp} instance
+ * @param mts the {@link MediaTimestamp} object whose data will be reused
+ * in the new Builder.
+ */
+ public Builder(@NonNull MediaTimestamp mts) {
+ if (mts == null) {
+ throw new IllegalArgumentException("null MediaTimestamp is not allowed");
+ }
+ mMediaTimeUs = mts.mediaTimeUs;
+ mNanoTime = mts.nanoTime;
+ mClockRate = mts.clockRate;
+ }
+
+ /**
+ * Combines all of the fields that have been set and return a new
+ * {@link MediaTimestamp} object.
+ *
+ * @return a new {@link MediaTimestamp} object
+ */
+ public @NonNull MediaTimestamp build() {
+ return new MediaTimestamp(mMediaTimeUs, mNanoTime, mClockRate);
+ }
+
+ /**
+ * Sets the info of media timestamp.
+ *
+ * @param mediaTimeUs the media time of the anchor in microseconds
+ * @param nanoTime the {@link java.lang.System#nanoTime system time} corresponding to
+ * the media time in nanoseconds.
+ * @param clockRate the rate of the media clock in relation to the system time.
+ * @return the same Builder instance.
+ */
+ public @NonNull Builder setMediaTimestamp(
+ long mediaTimeUs, long nanoTime, float clockRate) {
+ mMediaTimeUs = mediaTimeUs;
+ mNanoTime = nanoTime;
+ mClockRate = clockRate;
+
+ return this;
+ }
+ }
}
diff --git a/media/java/android/media/TimedMetaData.java b/media/java/android/media/TimedMetaData.java
index bcc18ef..2a89888 100644
--- a/media/java/android/media/TimedMetaData.java
+++ b/media/java/android/media/TimedMetaData.java
@@ -148,7 +148,7 @@
* It should not be null.
* @return the same Builder instance.
*/
- public @NonNull Builder setTimedMetaData(int timestamp, @NonNull byte[] metaData) {
+ public @NonNull Builder setTimedMetaData(long timestamp, @NonNull byte[] metaData) {
if (metaData == null) {
throw new IllegalArgumentException("null metaData is not allowed");
}
diff --git a/media/java/android/media/session/MediaSessionManager.java b/media/java/android/media/session/MediaSessionManager.java
index 5a9a7c8..6a06dd0 100644
--- a/media/java/android/media/session/MediaSessionManager.java
+++ b/media/java/android/media/session/MediaSessionManager.java
@@ -96,15 +96,9 @@
* @return The binder object from the system
* @hide
*/
- @SystemApi
public @NonNull ISession createSession(@NonNull MediaSession.CallbackStub cbStub,
- @NonNull String tag, int userId) {
- try {
- return mService.createSession(mContext.getPackageName(), cbStub, tag, userId);
- } catch (RemoteException e) {
- e.rethrowFromSystemServer();
- }
- return null;
+ @NonNull String tag, int userId) throws RemoteException {
+ return mService.createSession(mContext.getPackageName(), cbStub, tag, userId);
}
/**
diff --git a/packages/CarSystemUI/src/com/android/systemui/volume/CarVolumeDialogImpl.java b/packages/CarSystemUI/src/com/android/systemui/volume/CarVolumeDialogImpl.java
index d087176..1737b64 100644
--- a/packages/CarSystemUI/src/com/android/systemui/volume/CarVolumeDialogImpl.java
+++ b/packages/CarSystemUI/src/com/android/systemui/volume/CarVolumeDialogImpl.java
@@ -26,7 +26,6 @@
import android.car.Car;
import android.car.CarNotConnectedException;
import android.car.media.CarAudioManager;
-import android.car.media.ICarVolumeCallback;
import android.content.ComponentName;
import android.content.Context;
import android.content.DialogInterface;
@@ -106,7 +105,8 @@
private ListItemAdapter mPagedListAdapter;
private Car mCar;
private CarAudioManager mCarAudioManager;
- private final ICarVolumeCallback mVolumeChangeCallback = new ICarVolumeCallback.Stub() {
+ private final CarAudioManager.CarVolumeCallback mVolumeChangeCallback =
+ new CarAudioManager.CarVolumeCallback() {
@Override
public void onGroupVolumeChanged(int zoneId, int groupId, int flags) {
// TODO: Include zoneId into consideration.
@@ -162,7 +162,7 @@
if (mPagedListAdapter != null) {
mPagedListAdapter.notifyDataSetChanged();
}
- mCarAudioManager.registerVolumeCallback(mVolumeChangeCallback.asBinder());
+ mCarAudioManager.registerCarVolumeCallback(mVolumeChangeCallback);
} catch (CarNotConnectedException e) {
Log.e(TAG, "Car is not connected!", e);
}
@@ -440,11 +440,7 @@
}
private void cleanupAudioManager() {
- try {
- mCarAudioManager.unregisterVolumeCallback(mVolumeChangeCallback.asBinder());
- } catch (CarNotConnectedException e) {
- Log.e(TAG, "Car is not connected!", e);
- }
+ mCarAudioManager.unregisterCarVolumeCallback(mVolumeChangeCallback);
mVolumeLineItems.clear();
mCarAudioManager = null;
}
diff --git a/packages/FusedLocation/src/com/android/location/fused/FusedLocationProvider.java b/packages/FusedLocation/src/com/android/location/fused/FusedLocationProvider.java
index 87d6e4a..be817d6 100644
--- a/packages/FusedLocation/src/com/android/location/fused/FusedLocationProvider.java
+++ b/packages/FusedLocation/src/com/android/location/fused/FusedLocationProvider.java
@@ -23,7 +23,6 @@
import android.location.Criteria;
import android.os.Handler;
import android.os.Looper;
-import android.os.Message;
import android.os.UserHandle;
import android.os.WorkSource;
@@ -34,87 +33,53 @@
import java.io.FileDescriptor;
import java.io.PrintWriter;
-public class FusedLocationProvider extends LocationProviderBase implements FusionEngine.Callback {
+class FusedLocationProvider extends LocationProviderBase implements FusionEngine.Callback {
private static final String TAG = "FusedLocationProvider";
private static ProviderPropertiesUnbundled PROPERTIES = ProviderPropertiesUnbundled.create(
false, false, false, false, true, true, true, Criteria.POWER_LOW,
Criteria.ACCURACY_FINE);
- private static final int MSG_ENABLE = 1;
- private static final int MSG_DISABLE = 2;
- private static final int MSG_SET_REQUEST = 3;
-
+ private final Context mContext;
+ private final Handler mHandler;
private final FusionEngine mEngine;
- private static class RequestWrapper {
- public ProviderRequestUnbundled request;
- public WorkSource source;
- public RequestWrapper(ProviderRequestUnbundled request, WorkSource source) {
- this.request = request;
- this.source = source;
- }
- }
-
- public FusedLocationProvider(Context context) {
- super(TAG, PROPERTIES);
- mEngine = new FusionEngine(context, Looper.myLooper());
-
- // listen for user change
- IntentFilter intentFilter = new IntentFilter();
- intentFilter.addAction(Intent.ACTION_USER_SWITCHED);
- context.registerReceiverAsUser(new BroadcastReceiver() {
- @Override
- public void onReceive(Context context, Intent intent) {
- String action = intent.getAction();
- if (Intent.ACTION_USER_SWITCHED.equals(action)) {
- mEngine.switchUser();
- }
- }
- }, UserHandle.ALL, intentFilter, null, mHandler);
- }
-
- /**
- * For serializing requests to mEngine.
- */
- private Handler mHandler = new Handler() {
+ private final BroadcastReceiver mUserSwitchReceiver = new BroadcastReceiver() {
@Override
- public void handleMessage(Message msg) {
- switch (msg.what) {
- case MSG_ENABLE:
- mEngine.init(FusedLocationProvider.this);
- break;
- case MSG_DISABLE:
- mEngine.deinit();
- break;
- case MSG_SET_REQUEST:
- {
- RequestWrapper wrapper = (RequestWrapper) msg.obj;
- mEngine.setRequest(wrapper.request, wrapper.source);
- break;
- }
+ public void onReceive(Context context, Intent intent) {
+ String action = intent.getAction();
+ if (Intent.ACTION_USER_SWITCHED.equals(action)) {
+ mEngine.switchUser();
}
}
};
- @Override
- public void onEnable() {
- mHandler.sendEmptyMessage(MSG_ENABLE);
+ FusedLocationProvider(Context context) {
+ super(TAG, PROPERTIES);
+
+ mContext = context;
+ mHandler = new Handler(Looper.myLooper());
+ mEngine = new FusionEngine(context, Looper.myLooper(), this);
}
- @Override
- public void onDisable() {
- mHandler.sendEmptyMessage(MSG_DISABLE);
+ void init() {
+ // listen for user change
+ mContext.registerReceiverAsUser(mUserSwitchReceiver, UserHandle.ALL,
+ new IntentFilter(Intent.ACTION_USER_SWITCHED), null, mHandler);
+ }
+
+ void destroy() {
+ mContext.unregisterReceiver(mUserSwitchReceiver);
+ mHandler.post(() -> mEngine.setRequest(null));
}
@Override
public void onSetRequest(ProviderRequestUnbundled request, WorkSource source) {
- mHandler.obtainMessage(MSG_SET_REQUEST, new RequestWrapper(request, source)).sendToTarget();
+ mHandler.post(() -> mEngine.setRequest(request));
}
@Override
public void onDump(FileDescriptor fd, PrintWriter pw, String[] args) {
- // perform synchronously
mEngine.dump(fd, pw, args);
}
}
diff --git a/packages/FusedLocation/src/com/android/location/fused/FusedLocationService.java b/packages/FusedLocation/src/com/android/location/fused/FusedLocationService.java
index 12966cf..75bb5ec 100644
--- a/packages/FusedLocation/src/com/android/location/fused/FusedLocationService.java
+++ b/packages/FusedLocation/src/com/android/location/fused/FusedLocationService.java
@@ -21,27 +21,24 @@
import android.os.IBinder;
public class FusedLocationService extends Service {
+
private FusedLocationProvider mProvider;
@Override
public IBinder onBind(Intent intent) {
if (mProvider == null) {
- mProvider = new FusedLocationProvider(getApplicationContext());
+ mProvider = new FusedLocationProvider(this);
+ mProvider.init();
}
+
return mProvider.getBinder();
}
@Override
- public boolean onUnbind(Intent intent) {
- // make sure to stop performing work
- if (mProvider != null) {
- mProvider.onDisable();
- }
- return false;
- }
-
- @Override
public void onDestroy() {
- mProvider = null;
+ if (mProvider != null) {
+ mProvider.destroy();
+ mProvider = null;
+ }
}
}
diff --git a/packages/FusedLocation/src/com/android/location/fused/FusionEngine.java b/packages/FusedLocation/src/com/android/location/fused/FusionEngine.java
index 7a49524..e4610cf 100644
--- a/packages/FusedLocation/src/com/android/location/fused/FusionEngine.java
+++ b/packages/FusedLocation/src/com/android/location/fused/FusionEngine.java
@@ -16,14 +16,6 @@
package com.android.location.fused;
-import java.io.FileDescriptor;
-import java.io.PrintWriter;
-import java.util.HashMap;
-
-import com.android.location.provider.LocationProviderBase;
-import com.android.location.provider.LocationRequestUnbundled;
-import com.android.location.provider.ProviderRequestUnbundled;
-
import android.content.Context;
import android.location.Location;
import android.location.LocationListener;
@@ -32,9 +24,16 @@
import android.os.Looper;
import android.os.Parcelable;
import android.os.SystemClock;
-import android.os.WorkSource;
import android.util.Log;
+import com.android.location.provider.LocationProviderBase;
+import com.android.location.provider.LocationRequestUnbundled;
+import com.android.location.provider.ProviderRequestUnbundled;
+
+import java.io.FileDescriptor;
+import java.io.PrintWriter;
+import java.util.HashMap;
+
public class FusionEngine implements LocationListener {
public interface Callback {
void reportLocation(Location location);
@@ -47,72 +46,35 @@
public static final long SWITCH_ON_FRESHNESS_CLIFF_NS = 11 * 1000000000L; // 11 seconds
- private final Context mContext;
private final LocationManager mLocationManager;
private final Looper mLooper;
+ private final Callback mCallback;
// all fields are only used on mLooper thread. except for in dump() which is not thread-safe
- private Callback mCallback;
private Location mFusedLocation;
private Location mGpsLocation;
private Location mNetworkLocation;
- private boolean mEnabled;
private ProviderRequestUnbundled mRequest;
private final HashMap<String, ProviderStats> mStats = new HashMap<>();
- public FusionEngine(Context context, Looper looper) {
- mContext = context;
+ FusionEngine(Context context, Looper looper, Callback callback) {
mLocationManager = (LocationManager) context.getSystemService(Context.LOCATION_SERVICE);
mNetworkLocation = new Location("");
mNetworkLocation.setAccuracy(Float.MAX_VALUE);
mGpsLocation = new Location("");
mGpsLocation.setAccuracy(Float.MAX_VALUE);
mLooper = looper;
+ mCallback = callback;
mStats.put(GPS, new ProviderStats());
mStats.put(NETWORK, new ProviderStats());
-
- }
-
- public void init(Callback callback) {
- Log.i(TAG, "engine started (" + mContext.getPackageName() + ")");
- mCallback = callback;
- }
-
- /**
- * Called to stop doing any work, and release all resources
- * This can happen when a better fusion engine is installed
- * in a different package, and this one is no longer needed.
- * Called on mLooper thread
- */
- public void deinit() {
- mRequest = null;
- disable();
- Log.i(TAG, "engine stopped (" + mContext.getPackageName() + ")");
}
/** Called on mLooper thread */
- public void enable() {
- if (!mEnabled) {
- mEnabled = true;
- updateRequirements();
- }
- }
-
- /** Called on mLooper thread */
- public void disable() {
- if (mEnabled) {
- mEnabled = false;
- updateRequirements();
- }
- }
-
- /** Called on mLooper thread */
- public void setRequest(ProviderRequestUnbundled request, WorkSource source) {
+ public void setRequest(ProviderRequestUnbundled request) {
mRequest = request;
- mEnabled = request.getReportLocation();
updateRequirements();
}
@@ -120,6 +82,7 @@
public boolean requested;
public long requestTime;
public long minTime;
+
@Override
public String toString() {
return (requested ? " REQUESTED" : " ---");
@@ -154,7 +117,7 @@
}
private void updateRequirements() {
- if (!mEnabled || mRequest == null) {
+ if (mRequest == null || !mRequest.getReportLocation()) {
mRequest = null;
disableProvider(NETWORK);
disableProvider(GPS);
@@ -200,29 +163,30 @@
* Test whether one location (a) is better to use than another (b).
*/
private static boolean isBetterThan(Location locationA, Location locationB) {
- if (locationA == null) {
- return false;
- }
- if (locationB == null) {
- return true;
- }
- // A provider is better if the reading is sufficiently newer. Heading
- // underground can cause GPS to stop reporting fixes. In this case it's
- // appropriate to revert to cell, even when its accuracy is less.
- if (locationA.getElapsedRealtimeNanos() > locationB.getElapsedRealtimeNanos() + SWITCH_ON_FRESHNESS_CLIFF_NS) {
- return true;
- }
+ if (locationA == null) {
+ return false;
+ }
+ if (locationB == null) {
+ return true;
+ }
+ // A provider is better if the reading is sufficiently newer. Heading
+ // underground can cause GPS to stop reporting fixes. In this case it's
+ // appropriate to revert to cell, even when its accuracy is less.
+ if (locationA.getElapsedRealtimeNanos()
+ > locationB.getElapsedRealtimeNanos() + SWITCH_ON_FRESHNESS_CLIFF_NS) {
+ return true;
+ }
- // A provider is better if it has better accuracy. Assuming both readings
- // are fresh (and by that accurate), choose the one with the smaller
- // accuracy circle.
- if (!locationA.hasAccuracy()) {
- return false;
- }
- if (!locationB.hasAccuracy()) {
- return true;
- }
- return locationA.getAccuracy() < locationB.getAccuracy();
+ // A provider is better if it has better accuracy. Assuming both readings
+ // are fresh (and by that accurate), choose the one with the smaller
+ // accuracy circle.
+ if (!locationA.hasAccuracy()) {
+ return false;
+ }
+ if (!locationB.hasAccuracy()) {
+ return true;
+ }
+ return locationA.getAccuracy() < locationB.getAccuracy();
}
private void updateFusedLocation() {
@@ -252,9 +216,9 @@
}
if (mCallback != null) {
- mCallback.reportLocation(mFusedLocation);
+ mCallback.reportLocation(mFusedLocation);
} else {
- Log.w(TAG, "Location updates received while fusion engine not started");
+ Log.w(TAG, "Location updates received while fusion engine not started");
}
}
@@ -272,19 +236,22 @@
/** Called on mLooper thread */
@Override
- public void onStatusChanged(String provider, int status, Bundle extras) { }
+ public void onStatusChanged(String provider, int status, Bundle extras) {
+ }
/** Called on mLooper thread */
@Override
- public void onProviderEnabled(String provider) { }
+ public void onProviderEnabled(String provider) {
+ }
/** Called on mLooper thread */
@Override
- public void onProviderDisabled(String provider) { }
+ public void onProviderDisabled(String provider) {
+ }
public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
StringBuilder s = new StringBuilder();
- s.append("mEnabled=").append(mEnabled).append(' ').append(mRequest).append('\n');
+ s.append(mRequest).append('\n');
s.append("fused=").append(mFusedLocation).append('\n');
s.append(String.format("gps %s\n", mGpsLocation));
s.append(" ").append(mStats.get(GPS)).append('\n');
diff --git a/packages/MtpDocumentsProvider/src/com/android/mtp/MtpManager.java b/packages/MtpDocumentsProvider/src/com/android/mtp/MtpManager.java
index 8f254e9..a7de631 100644
--- a/packages/MtpDocumentsProvider/src/com/android/mtp/MtpManager.java
+++ b/packages/MtpDocumentsProvider/src/com/android/mtp/MtpManager.java
@@ -200,7 +200,7 @@
}
if (objectInfo.getFormat() != MtpConstants.FORMAT_ASSOCIATION) {
if (!device.sendObject(sendObjectInfoResult.getObjectHandle(),
- sendObjectInfoResult.getCompressedSize(), source)) {
+ sendObjectInfoResult.getCompressedSizeLong(), source)) {
throw new IOException("Failed to send contents of a document");
}
}
diff --git a/packages/PrintSpooler/AndroidManifest.xml b/packages/PrintSpooler/AndroidManifest.xml
index 03eafc4..478ee54 100644
--- a/packages/PrintSpooler/AndroidManifest.xml
+++ b/packages/PrintSpooler/AndroidManifest.xml
@@ -51,6 +51,7 @@
<application
android:allowClearUserData="true"
android:label="@string/app_label"
+ android:icon="@drawable/ic_app_icon"
android:supportsRtl="true">
<service
diff --git a/packages/PrintSpooler/res/drawable/app_icon_foreground.xml b/packages/PrintSpooler/res/drawable/app_icon_foreground.xml
new file mode 100644
index 0000000..249e387
--- /dev/null
+++ b/packages/PrintSpooler/res/drawable/app_icon_foreground.xml
@@ -0,0 +1,34 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ ~ 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.
+ -->
+<inset
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ android:insetTop="25%"
+ android:insetRight="25%"
+ android:insetBottom="25%"
+ android:insetLeft="25%">
+
+ <vector
+ android:width="36dp"
+ android:height="36dp"
+ android:viewportWidth="24"
+ android:viewportHeight="24">
+
+ <path
+ android:fillColor="#FFFFFF"
+ android:pathData="M19,8L5,8c-1.66,0 -3,1.34 -3,3v6h4v4h12v-4h4v-6c0,-1.66 -1.34,-3 -3,-3zM16,19L8,19v-5h8v5zM19,12c-0.55,0 -1,-0.45 -1,-1s0.45,-1 1,-1 1,0.45 1,1 -0.45,1 -1,1zM18,3L6,3v4h12L18,3z" />
+ </vector>
+</inset>
diff --git a/packages/PrintSpooler/res/drawable/ic_app_icon.xml b/packages/PrintSpooler/res/drawable/ic_app_icon.xml
new file mode 100644
index 0000000..82c18e0
--- /dev/null
+++ b/packages/PrintSpooler/res/drawable/ic_app_icon.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ 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.
+ -->
+
+<adaptive-icon xmlns:android="http://schemas.android.com/apk/res/android">
+ <background android:drawable="@*android:color/accent_device_default_light"/>
+ <foreground android:drawable="@drawable/app_icon_foreground"/>
+</adaptive-icon>
\ No newline at end of file
diff --git a/packages/SettingsLib/SearchWidget/res/drawable/ic_search_24dp.xml b/packages/SettingsLib/SearchWidget/res/drawable/ic_search_24dp.xml
index 7e65848..a046332 100644
--- a/packages/SettingsLib/SearchWidget/res/drawable/ic_search_24dp.xml
+++ b/packages/SettingsLib/SearchWidget/res/drawable/ic_search_24dp.xml
@@ -20,7 +20,7 @@
android:height="24dp"
android:viewportWidth="24"
android:viewportHeight="24"
- android:tint="?android:attr/colorControlNormal">
+ android:tint="?android:attr/colorAccent">
<path
android:fillColor="#FF000000"
android:pathData="M20.49,19l-5.73,-5.73C15.53,12.2 16,10.91 16,9.5C16,5.91 13.09,3 9.5,3S3,5.91 3,9.5C3,13.09 5.91,16 9.5,16c1.41,0 2.7,-0.47 3.77,-1.24L19,20.49L20.49,19zM5,9.5C5,7.01 7.01,5 9.5,5S14,7.01 14,9.5S11.99,14 9.5,14S5,11.99 5,9.5z"/>
diff --git a/packages/SettingsLib/src/com/android/settingslib/RestrictedLockUtilsInternal.java b/packages/SettingsLib/src/com/android/settingslib/RestrictedLockUtilsInternal.java
index 1457fcf..74aaf3c 100644
--- a/packages/SettingsLib/src/com/android/settingslib/RestrictedLockUtilsInternal.java
+++ b/packages/SettingsLib/src/com/android/settingslib/RestrictedLockUtilsInternal.java
@@ -38,6 +38,7 @@
import android.text.Spanned;
import android.text.style.ForegroundColorSpan;
import android.text.style.ImageSpan;
+import android.util.Log;
import android.view.MenuItem;
import android.widget.TextView;
@@ -52,6 +53,9 @@
* support message dialog.
*/
public class RestrictedLockUtilsInternal extends RestrictedLockUtils {
+
+ private static final String LOG_TAG = "RestrictedLockUtils";
+
/**
* @return drawables for displaying with settings that are locked by a device admin.
*/
@@ -305,6 +309,42 @@
return null;
}
+ /**
+ * @param userId user id of a managed profile.
+ * @return profile owner admin if cross profile calendar is disallowed.
+ */
+ public static EnforcedAdmin getCrossProfileCalendarEnforcingAdmin(Context context, int userId) {
+ final Context managedProfileContext = createPackageContextAsUser(
+ context, userId);
+ final DevicePolicyManager dpm = managedProfileContext.getSystemService(
+ DevicePolicyManager.class);
+ if (dpm == null) {
+ return null;
+ }
+ final EnforcedAdmin admin = getProfileOwner(context, userId);
+ if (admin == null) {
+ return null;
+ }
+ if (dpm.getCrossProfileCalendarPackages().isEmpty()) {
+ return admin;
+ }
+ return null;
+ }
+
+ /**
+ * @param userId user id of a managed profile.
+ * @return a context created from the given context for the given user, or null if it fails.
+ */
+ private static Context createPackageContextAsUser(Context context, int userId) {
+ try {
+ return context.createPackageContextAsUser(
+ context.getPackageName(), 0 /* flags */, UserHandle.of(userId));
+ } catch (PackageManager.NameNotFoundException e) {
+ Log.e(LOG_TAG, "Failed to create user context", e);
+ }
+ return null;
+ }
+
public static EnforcedAdmin checkIfAccessibilityServiceDisallowed(Context context,
String packageName, int userId) {
DevicePolicyManager dpm = (DevicePolicyManager) context.getSystemService(
diff --git a/packages/SettingsLib/src/com/android/settingslib/applications/PermissionsSummaryHelper.java b/packages/SettingsLib/src/com/android/settingslib/applications/PermissionsSummaryHelper.java
index ec8e956..f2b97b4 100644
--- a/packages/SettingsLib/src/com/android/settingslib/applications/PermissionsSummaryHelper.java
+++ b/packages/SettingsLib/src/com/android/settingslib/applications/PermissionsSummaryHelper.java
@@ -17,8 +17,8 @@
import android.annotation.NonNull;
import android.content.Context;
-import android.content.pm.permission.RuntimePermissionPresentationInfo;
-import android.content.pm.permission.RuntimePermissionPresenter;
+import android.permission.RuntimePermissionPresentationInfo;
+import android.permission.RuntimePermissionPresenter;
import java.text.Collator;
import java.util.ArrayList;
diff --git a/packages/SettingsLib/src/com/android/settingslib/bluetooth/CachedBluetoothDevice.java b/packages/SettingsLib/src/com/android/settingslib/bluetooth/CachedBluetoothDevice.java
index 9270d13..1bffff7 100644
--- a/packages/SettingsLib/src/com/android/settingslib/bluetooth/CachedBluetoothDevice.java
+++ b/packages/SettingsLib/src/com/android/settingslib/bluetooth/CachedBluetoothDevice.java
@@ -71,15 +71,8 @@
boolean mJustDiscovered;
- private int mMessageRejectionCount;
-
private final Collection<Callback> mCallbacks = new ArrayList<>();
- // How many times user should reject the connection to make the choice persist.
- private final static int MESSAGE_REJECTION_COUNT_LIMIT_TO_PERSIST = 2;
-
- private final static String MESSAGE_REJECTION_COUNT_PREFS_NAME = "bluetooth_message_reject";
-
/**
* Last time a bt profile auto-connect was attempted.
* If an ACTION_UUID intent comes in within
@@ -348,7 +341,6 @@
fetchActiveDevices();
migratePhonebookPermissionChoice();
migrateMessagePermissionChoice();
- fetchMessageRejectionCount();
dispatchAttributesChanged();
}
@@ -642,8 +634,6 @@
mDevice.setPhonebookAccessPermission(BluetoothDevice.ACCESS_UNKNOWN);
mDevice.setMessageAccessPermission(BluetoothDevice.ACCESS_UNKNOWN);
mDevice.setSimAccessPermission(BluetoothDevice.ACCESS_UNKNOWN);
- mMessageRejectionCount = 0;
- saveMessageRejectionCount();
}
refresh();
@@ -797,34 +787,6 @@
editor.commit();
}
- /**
- * @return Whether this rejection should persist.
- */
- public boolean checkAndIncreaseMessageRejectionCount() {
- if (mMessageRejectionCount < MESSAGE_REJECTION_COUNT_LIMIT_TO_PERSIST) {
- mMessageRejectionCount++;
- saveMessageRejectionCount();
- }
- return mMessageRejectionCount >= MESSAGE_REJECTION_COUNT_LIMIT_TO_PERSIST;
- }
-
- private void fetchMessageRejectionCount() {
- SharedPreferences preference = mContext.getSharedPreferences(
- MESSAGE_REJECTION_COUNT_PREFS_NAME, Context.MODE_PRIVATE);
- mMessageRejectionCount = preference.getInt(mDevice.getAddress(), 0);
- }
-
- private void saveMessageRejectionCount() {
- SharedPreferences.Editor editor = mContext.getSharedPreferences(
- MESSAGE_REJECTION_COUNT_PREFS_NAME, Context.MODE_PRIVATE).edit();
- if (mMessageRejectionCount == 0) {
- editor.remove(mDevice.getAddress());
- } else {
- editor.putInt(mDevice.getAddress(), mMessageRejectionCount);
- }
- editor.commit();
- }
-
private void processPhonebookAccess() {
if (mDevice.getBondState() != BluetoothDevice.BOND_BONDED) return;
diff --git a/packages/SettingsLib/src/com/android/settingslib/drawer/TileUtils.java b/packages/SettingsLib/src/com/android/settingslib/drawer/TileUtils.java
index 67cfe6b..91892ab 100644
--- a/packages/SettingsLib/src/com/android/settingslib/drawer/TileUtils.java
+++ b/packages/SettingsLib/src/com/android/settingslib/drawer/TileUtils.java
@@ -363,7 +363,8 @@
return null;
}
try {
- return provider.call(context.getPackageName(), method, uriString, null);
+ return provider.call(context.getPackageName(), uri.getAuthority(),
+ method, uriString, null);
} catch (RemoteException e) {
return null;
}
diff --git a/packages/SettingsProvider/src/com/android/providers/settings/DeviceConfigService.java b/packages/SettingsProvider/src/com/android/providers/settings/DeviceConfigService.java
new file mode 100644
index 0000000..3520918
--- /dev/null
+++ b/packages/SettingsProvider/src/com/android/providers/settings/DeviceConfigService.java
@@ -0,0 +1,355 @@
+/*
+ * 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.providers.settings;
+
+import android.annotation.Nullable;
+import android.annotation.SystemApi;
+import android.app.ActivityManager;
+import android.content.IContentProvider;
+import android.net.Uri;
+import android.os.Binder;
+import android.os.Bundle;
+import android.os.Process;
+import android.os.RemoteException;
+import android.os.ResultReceiver;
+import android.os.ShellCallback;
+import android.os.ShellCommand;
+import android.provider.Settings;
+
+import java.io.FileDescriptor;
+import java.io.PrintWriter;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+/**
+ * Receives shell commands from the command line related to device config flags, and dispatches them
+ * to the SettingsProvider.
+ *
+ * @hide
+ */
+@SystemApi
+public final class DeviceConfigService extends Binder {
+ /**
+ * TODO(b/113100523): Move this to DeviceConfig.java when it is added, and expose it as a System
+ * API.
+ */
+ private static final Uri CONFIG_CONTENT_URI =
+ Uri.parse("content://" + Settings.AUTHORITY + "/config");
+
+ final SettingsProvider mProvider;
+
+ public DeviceConfigService(SettingsProvider provider) {
+ mProvider = provider;
+ }
+
+ @Override
+ public void onShellCommand(FileDescriptor in, FileDescriptor out, FileDescriptor err,
+ String[] args, ShellCallback callback, ResultReceiver resultReceiver) {
+ (new MyShellCommand(mProvider)).exec(this, in, out, err, args, callback, resultReceiver);
+ }
+
+ static final class MyShellCommand extends ShellCommand {
+ final SettingsProvider mProvider;
+
+ enum CommandVerb {
+ UNSPECIFIED,
+ GET,
+ PUT,
+ DELETE,
+ LIST,
+ RESET,
+ }
+
+ MyShellCommand(SettingsProvider provider) {
+ mProvider = provider;
+ }
+
+ @Override
+ public int onCommand(String cmd) {
+ if (cmd == null || "help".equals(cmd) || "-h".equals(cmd)) {
+ onHelp();
+ return -1;
+ }
+
+ final PrintWriter perr = getErrPrintWriter();
+ boolean isValid = false;
+ CommandVerb verb;
+ if ("get".equalsIgnoreCase(cmd)) {
+ verb = CommandVerb.GET;
+ } else if ("put".equalsIgnoreCase(cmd)) {
+ verb = CommandVerb.PUT;
+ } else if ("delete".equalsIgnoreCase(cmd)) {
+ verb = CommandVerb.DELETE;
+ } else if ("list".equalsIgnoreCase(cmd)) {
+ verb = CommandVerb.LIST;
+ if (peekNextArg() == null) {
+ isValid = true;
+ }
+ } else if ("reset".equalsIgnoreCase(cmd)) {
+ verb = CommandVerb.RESET;
+ } else {
+ // invalid
+ perr.println("Invalid command: " + cmd);
+ return -1;
+ }
+
+ int resetMode = -1;
+ boolean makeDefault = false;
+ String namespace = null;
+ String key = null;
+ String value = null;
+ String arg = null;
+ while ((arg = getNextArg()) != null) {
+ if (verb == CommandVerb.RESET) {
+ if (resetMode == -1) {
+ if ("untrusted_defaults".equalsIgnoreCase(arg)) {
+ resetMode = Settings.RESET_MODE_UNTRUSTED_DEFAULTS;
+ } else if ("untrusted_clear".equalsIgnoreCase(arg)) {
+ resetMode = Settings.RESET_MODE_UNTRUSTED_CHANGES;
+ } else if ("trusted_defaults".equalsIgnoreCase(arg)) {
+ resetMode = Settings.RESET_MODE_TRUSTED_DEFAULTS;
+ } else {
+ // invalid
+ perr.println("Invalid reset mode: " + arg);
+ return -1;
+ }
+ if (peekNextArg() == null) {
+ isValid = true;
+ }
+ } else {
+ namespace = arg;
+ if (peekNextArg() == null) {
+ isValid = true;
+ } else {
+ // invalid
+ perr.println("Too many arguments");
+ return -1;
+ }
+ }
+ } else if (namespace == null) {
+ namespace = arg;
+ if (verb == CommandVerb.LIST) {
+ if (peekNextArg() == null) {
+ isValid = true;
+ } else {
+ // invalid
+ perr.println("Too many arguments");
+ return -1;
+ }
+ }
+ } else if (key == null) {
+ key = arg;
+ if ((verb == CommandVerb.GET || verb == CommandVerb.DELETE)) {
+ if (peekNextArg() == null) {
+ isValid = true;
+ } else {
+ // invalid
+ perr.println("Too many arguments");
+ return -1;
+ }
+ }
+ } else if (value == null) {
+ value = arg;
+ if (verb == CommandVerb.PUT && peekNextArg() == null) {
+ isValid = true;
+ }
+ } else if ("default".equalsIgnoreCase(arg)) {
+ makeDefault = true;
+ if (verb == CommandVerb.PUT && peekNextArg() == null) {
+ isValid = true;
+ } else {
+ // invalid
+ perr.println("Too many arguments");
+ return -1;
+ }
+ }
+ }
+
+ if (!isValid) {
+ perr.println("Bad arguments");
+ return -1;
+ }
+
+ final IContentProvider iprovider = mProvider.getIContentProvider();
+ final PrintWriter pout = getOutPrintWriter();
+ switch (verb) {
+ case GET:
+ pout.println(get(iprovider, namespace, key));
+ break;
+ case PUT:
+ put(iprovider, namespace, key, value, makeDefault);
+ break;
+ case DELETE:
+ pout.println(delete(iprovider, namespace, key)
+ ? "Successfully deleted " + key + " from " + namespace
+ : "Failed to delete " + key + " from " + namespace);
+ break;
+ case LIST:
+ for (String line : list(iprovider, namespace)) {
+ pout.println(line);
+ }
+ break;
+ case RESET:
+ reset(iprovider, resetMode, namespace);
+ break;
+ default:
+ perr.println("Unspecified command");
+ return -1;
+ }
+ return 0;
+ }
+
+ @Override
+ public void onHelp() {
+ PrintWriter pw = getOutPrintWriter();
+ pw.println("Device Config (device_config) commands:");
+ pw.println(" help");
+ pw.println(" Print this help text.");
+ pw.println(" get NAMESPACE KEY");
+ pw.println(" Retrieve the current value of KEY from the given NAMESPACE.");
+ pw.println(" put NAMESPACE KEY VALUE [default]");
+ pw.println(" Change the contents of KEY to VALUE for the given NAMESPACE.");
+ pw.println(" {default} to set as the default value.");
+ pw.println(" delete NAMESPACE KEY");
+ pw.println(" Delete the entry for KEY for the given NAMESPACE.");
+ pw.println(" list [NAMESPACE]");
+ pw.println(" Print all keys and values defined, optionally for the given "
+ + "NAMESPACE.");
+ pw.println(" reset RESET_MODE [NAMESPACE]");
+ pw.println(" Reset all flag values, optionally for a NAMESPACE, according to "
+ + "RESET_MODE.");
+ pw.println(" RESET_MODE is one of {untrusted_defaults, untrusted_clear, "
+ + "trusted_defaults}");
+ pw.println(" NAMESPACE limits which flags are reset if provided, otherwise all "
+ + "flags are reset");
+ }
+
+ private String get(IContentProvider provider, String namespace, String key) {
+ String compositeKey = namespace + "/" + key;
+ String result = null;
+ try {
+ Bundle args = new Bundle();
+ args.putInt(Settings.CALL_METHOD_USER_KEY,
+ ActivityManager.getService().getCurrentUser().id);
+ Bundle b = provider.call(resolveCallingPackage(), Settings.CALL_METHOD_GET_CONFIG,
+ compositeKey, args);
+ if (b != null) {
+ result = b.getPairValue();
+ }
+ } catch (RemoteException e) {
+ throw new RuntimeException("Failed in IPC", e);
+ }
+ return result;
+ }
+
+ private void put(IContentProvider provider, String namespace, String key, String value,
+ boolean makeDefault) {
+ String compositeKey = namespace + "/" + key;
+
+ try {
+ Bundle args = new Bundle();
+ args.putString(Settings.NameValueTable.VALUE, value);
+ args.putInt(Settings.CALL_METHOD_USER_KEY,
+ ActivityManager.getService().getCurrentUser().id);
+ if (makeDefault) {
+ args.putBoolean(Settings.CALL_METHOD_MAKE_DEFAULT_KEY, true);
+ }
+ provider.call(resolveCallingPackage(), Settings.CALL_METHOD_PUT_CONFIG,
+ compositeKey, args);
+ } catch (RemoteException e) {
+ throw new RuntimeException("Failed in IPC", e);
+ }
+ }
+
+ private boolean delete(IContentProvider provider, String namespace, String key) {
+ String compositeKey = namespace + "/" + key;
+ boolean success;
+
+ try {
+ Bundle args = new Bundle();
+ args.putInt(Settings.CALL_METHOD_USER_KEY,
+ ActivityManager.getService().getCurrentUser().id);
+ Bundle b = provider.call(resolveCallingPackage(),
+ Settings.CALL_METHOD_DELETE_CONFIG, compositeKey, args);
+ success = (b != null && b.getInt(SettingsProvider.RESULT_ROWS_DELETED) == 1);
+ } catch (RemoteException e) {
+ throw new RuntimeException("Failed in IPC", e);
+ }
+ return success;
+ }
+
+ private List<String> list(IContentProvider provider, @Nullable String namespace) {
+ final ArrayList<String> lines = new ArrayList<>();
+
+ try {
+ Bundle args = new Bundle();
+ args.putInt(Settings.CALL_METHOD_USER_KEY,
+ ActivityManager.getService().getCurrentUser().id);
+ if (namespace != null) {
+ args.putString(Settings.CALL_METHOD_PREFIX_KEY, namespace);
+ }
+ Bundle b = provider.call(resolveCallingPackage(),
+ Settings.CALL_METHOD_LIST_CONFIG, null, args);
+ if (b != null) {
+ Map<String, String> flagsToValues =
+ (HashMap) b.getSerializable(Settings.NameValueTable.VALUE);
+ for (String key : flagsToValues.keySet()) {
+ lines.add(key + "=" + flagsToValues.get(key));
+ }
+ }
+
+ Collections.sort(lines);
+ } catch (RemoteException e) {
+ throw new RuntimeException("Failed in IPC", e);
+ }
+ return lines;
+ }
+
+ private void reset(IContentProvider provider, int resetMode, @Nullable String namespace) {
+ try {
+ Bundle args = new Bundle();
+ args.putInt(Settings.CALL_METHOD_USER_KEY,
+ ActivityManager.getService().getCurrentUser().id);
+ args.putInt(Settings.CALL_METHOD_RESET_MODE_KEY, resetMode);
+ args.putString(Settings.CALL_METHOD_PREFIX_KEY, namespace);
+ provider.call(
+ resolveCallingPackage(), Settings.CALL_METHOD_RESET_CONFIG, null, args);
+ } catch (RemoteException e) {
+ throw new RuntimeException("Failed in IPC", e);
+ }
+ }
+
+ private static String resolveCallingPackage() {
+ switch (Binder.getCallingUid()) {
+ case Process.ROOT_UID: {
+ return "root";
+ }
+
+ case Process.SHELL_UID: {
+ return "com.android.shell";
+ }
+
+ default: {
+ return null;
+ }
+ }
+ }
+ }
+}
diff --git a/packages/SettingsProvider/src/com/android/providers/settings/SettingsProtoDumpUtil.java b/packages/SettingsProvider/src/com/android/providers/settings/SettingsProtoDumpUtil.java
index ad88432..e3d3d81 100644
--- a/packages/SettingsProvider/src/com/android/providers/settings/SettingsProtoDumpUtil.java
+++ b/packages/SettingsProvider/src/com/android/providers/settings/SettingsProtoDumpUtil.java
@@ -208,9 +208,14 @@
GlobalSettingsProto.Autofill.MAX_VISIBLE_DATASETS);
p.end(autofillToken);
+ final long backupToken = p.start(GlobalSettingsProto.BACKUP);
dumpSetting(s, p,
Settings.Global.BACKUP_AGENT_TIMEOUT_PARAMETERS,
- GlobalSettingsProto.BACKUP_AGENT_TIMEOUT_PARAMETERS);
+ GlobalSettingsProto.Backup.BACKUP_AGENT_TIMEOUT_PARAMETERS);
+ dumpSetting(s, p,
+ Settings.Global.BACKUP_MULTI_USER_ENABLED,
+ GlobalSettingsProto.Backup.BACKUP_MULTI_USER_ENABLED);
+ p.end(backupToken);
final long batteryToken = p.start(GlobalSettingsProto.BATTERY);
dumpSetting(s, p,
@@ -685,8 +690,14 @@
Settings.Global.GPU_DEBUG_LAYERS,
GlobalSettingsProto.Gpu.DEBUG_LAYERS);
dumpSetting(s, p,
- Settings.Global.ANGLE_ENABLED_APP,
- GlobalSettingsProto.Gpu.ANGLE_ENABLED_APP);
+ Settings.Global.GLOBAL_SETTINGS_ANGLE_GL_DRIVER_ALL_ANGLE,
+ GlobalSettingsProto.Gpu.ANGLE_GL_DRIVER_ALL_ANGLE);
+ dumpSetting(s, p,
+ Settings.Global.GLOBAL_SETTINGS_ANGLE_GL_DRIVER_SELECTION_PKGS,
+ GlobalSettingsProto.Gpu.ANGLE_GL_DRIVER_SELECTION_PKGS);
+ dumpSetting(s, p,
+ Settings.Global.GLOBAL_SETTINGS_ANGLE_GL_DRIVER_SELECTION_VALUES,
+ GlobalSettingsProto.Gpu.ANGLE_GL_DRIVER_SELECTION_VALUES);
dumpSetting(s, p,
Settings.Global.GPU_DEBUG_LAYER_APP,
GlobalSettingsProto.Gpu.DEBUG_LAYER_APP);
@@ -1004,6 +1015,9 @@
dumpSetting(s, p,
Settings.Global.SMART_REPLIES_IN_NOTIFICATIONS_FLAGS,
GlobalSettingsProto.Notification.SMART_REPLIES_IN_NOTIFICATIONS_FLAGS);
+ dumpSetting(s, p,
+ Settings.Global.SMART_SUGGESTIONS_IN_NOTIFICATIONS_FLAGS,
+ GlobalSettingsProto.Notification.SMART_SUGGESTIONS_IN_NOTIFICATIONS_FLAGS);
p.end(notificationToken);
dumpSetting(s, p,
diff --git a/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java b/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java
index 00ea45c..424368d 100644
--- a/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java
+++ b/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java
@@ -94,6 +94,7 @@
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
+import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Locale;
@@ -147,6 +148,7 @@
private static final String TABLE_SYSTEM = "system";
private static final String TABLE_SECURE = "secure";
private static final String TABLE_GLOBAL = "global";
+ private static final String TABLE_CONFIG = "config";
// Old tables no longer exist.
private static final String TABLE_FAVORITES = "favorites";
@@ -333,6 +335,7 @@
startWatchingUserRestrictionChanges();
});
ServiceManager.addService("settings", new SettingsService(this));
+ ServiceManager.addService("device_config", new DeviceConfigService(this));
return true;
}
@@ -414,9 +417,8 @@
case Settings.CALL_METHOD_PUT_CONFIG: {
String value = getSettingValue(args);
- String tag = getSettingTag(args);
final boolean makeDefault = getSettingMakeDefault(args);
- insertConfigSetting(name, value, tag, makeDefault, requestingUserId, false);
+ insertConfigSetting(name, value, null, makeDefault, requestingUserId, false);
break;
}
@@ -444,8 +446,8 @@
case Settings.CALL_METHOD_RESET_CONFIG: {
final int mode = getResetModeEnforcingPermission(args);
- String tag = getSettingTag(args);
- resetConfigSetting(requestingUserId, mode, tag);
+ String prefix = getSettingPrefix(args);
+ resetConfigSetting(requestingUserId, mode, prefix);
break;
}
@@ -463,15 +465,8 @@
break;
}
- case Settings.CALL_METHOD_DELETE_SYSTEM: {
- int rows = deleteSystemSetting(name, requestingUserId) ? 1 : 0;
- Bundle result = new Bundle();
- result.putInt(RESULT_ROWS_DELETED, rows);
- return result;
- }
-
- case Settings.CALL_METHOD_DELETE_SECURE: {
- int rows = deleteSecureSetting(name, requestingUserId, false) ? 1 : 0;
+ case Settings.CALL_METHOD_DELETE_CONFIG: {
+ int rows = deleteConfigSetting(name, requestingUserId, false) ? 1 : 0;
Bundle result = new Bundle();
result.putInt(RESULT_ROWS_DELETED, rows);
return result;
@@ -484,10 +479,32 @@
return result;
}
- case Settings.CALL_METHOD_LIST_SYSTEM: {
+ case Settings.CALL_METHOD_DELETE_SECURE: {
+ int rows = deleteSecureSetting(name, requestingUserId, false) ? 1 : 0;
+ Bundle result = new Bundle();
+ result.putInt(RESULT_ROWS_DELETED, rows);
+ return result;
+ }
+
+ case Settings.CALL_METHOD_DELETE_SYSTEM: {
+ int rows = deleteSystemSetting(name, requestingUserId) ? 1 : 0;
+ Bundle result = new Bundle();
+ result.putInt(RESULT_ROWS_DELETED, rows);
+ return result;
+ }
+
+ case Settings.CALL_METHOD_LIST_CONFIG: {
+ String prefix = getSettingPrefix(args);
+ Bundle result = new Bundle();
+ result.putSerializable(
+ Settings.NameValueTable.VALUE, (HashMap) getAllConfigFlags(prefix));
+ return result;
+ }
+
+ case Settings.CALL_METHOD_LIST_GLOBAL: {
Bundle result = new Bundle();
result.putStringArrayList(RESULT_SETTINGS_LIST,
- buildSettingsList(getAllSystemSettings(requestingUserId, null)));
+ buildSettingsList(getAllGlobalSettings(null)));
return result;
}
@@ -498,10 +515,10 @@
return result;
}
- case Settings.CALL_METHOD_LIST_GLOBAL: {
+ case Settings.CALL_METHOD_LIST_SYSTEM: {
Bundle result = new Bundle();
result.putStringArrayList(RESULT_SETTINGS_LIST,
- buildSettingsList(getAllGlobalSettings(null)));
+ buildSettingsList(getAllSystemSettings(requestingUserId, null)));
return result;
}
@@ -1061,36 +1078,47 @@
MUTATION_OPERATION_INSERT, forceNotify, 0);
}
- private void resetConfigSetting(int requestingUserId, int mode, String tag) {
+ private boolean deleteConfigSetting(String name, int requestingUserId, boolean forceNotify) {
+ if (DEBUG) {
+ Slog.v(LOG_TAG, "deleteConfigSetting(" + name + ", " + requestingUserId
+ + ", " + forceNotify + ")");
+ }
+ return mutateConfigSetting(name, null, null, false, requestingUserId,
+ MUTATION_OPERATION_DELETE, forceNotify, 0);
+ }
+
+ private void resetConfigSetting(int requestingUserId, int mode, String prefix) {
if (DEBUG) {
Slog.v(LOG_TAG, "resetConfigSetting(" + requestingUserId + ", "
- + mode + ", " + tag + ")");
+ + mode + ", " + prefix + ")");
}
- mutateConfigSetting(null, null, tag, false, requestingUserId,
+ mutateConfigSetting(null, null, prefix, false, requestingUserId,
MUTATION_OPERATION_RESET, false, mode);
}
- private boolean mutateConfigSetting(String name, String value, String tag,
+ private boolean mutateConfigSetting(String name, String value, String prefix,
boolean makeDefault, int requestingUserId, int operation, boolean forceNotify,
int mode) {
// TODO(b/117663715): check the new permission when it's added.
// enforceWritePermission(Manifest.permission.WRITE_SECURE_SETTINGS);
- // Resolve the userId on whose behalf the call is made.
- final int callingUserId = resolveCallingUserIdEnforcingPermissionsLocked(requestingUserId);
-
// Perform the mutation.
synchronized (mLock) {
switch (operation) {
case MUTATION_OPERATION_INSERT: {
return mSettingsRegistry.insertSettingLocked(SETTINGS_TYPE_CONFIG,
- UserHandle.USER_SYSTEM, name, value, tag, makeDefault,
+ UserHandle.USER_SYSTEM, name, value, null, makeDefault,
getCallingPackage(), forceNotify, null);
}
+ case MUTATION_OPERATION_DELETE: {
+ return mSettingsRegistry.deleteSettingLocked(SETTINGS_TYPE_CONFIG,
+ UserHandle.USER_SYSTEM, name, forceNotify, null);
+ }
+
case MUTATION_OPERATION_RESET: {
mSettingsRegistry.resetSettingsLocked(SETTINGS_TYPE_CONFIG,
- UserHandle.USER_SYSTEM, getCallingPackage(), mode, tag);
+ UserHandle.USER_SYSTEM, getCallingPackage(), mode, null, prefix);
} return true;
}
}
@@ -1098,6 +1126,34 @@
return false;
}
+ private Map<String, String> getAllConfigFlags(@Nullable String prefix) {
+ if (DEBUG) {
+ Slog.v(LOG_TAG, "getAllConfigFlags() for " + prefix);
+ }
+
+ synchronized (mLock) {
+ // Get the settings.
+ SettingsState settingsState = mSettingsRegistry.getSettingsLocked(
+ SETTINGS_TYPE_CONFIG, UserHandle.USER_SYSTEM);
+
+ List<String> names = getSettingsNamesLocked(SETTINGS_TYPE_CONFIG,
+ UserHandle.USER_SYSTEM);
+
+ final int nameCount = names.size();
+ Map<String, String> flagsToValues = new HashMap<>(names.size());
+
+ for (int i = 0; i < nameCount; i++) {
+ String name = names.get(i);
+ Setting setting = settingsState.getSettingLocked(name);
+ if (prefix == null || setting.getName().startsWith(prefix)) {
+ flagsToValues.put(setting.getName(), setting.getValue());
+ }
+ }
+
+ return flagsToValues;
+ }
+ }
+
private Cursor getAllGlobalSettings(String[] projection) {
if (DEBUG) {
Slog.v(LOG_TAG, "getAllGlobalSettings()");
@@ -2085,6 +2141,13 @@
return (args != null) ? args.getString(Settings.CALL_METHOD_TAG_KEY) : null;
}
+ private static String getSettingPrefix(Bundle args) {
+ String prefix = (args != null) ? args.getString(Settings.CALL_METHOD_PREFIX_KEY) : null;
+ // Append '/' to ensure we only match properties with this exact prefix.
+ // i.e. "foo" should match "foo/property" but not "foobar/property"
+ return prefix != null ? prefix + "/" : null;
+ }
+
private static boolean getSettingMakeDefault(Bundle args) {
return (args != null) && args.getBoolean(Settings.CALL_METHOD_MAKE_DEFAULT_KEY);
}
@@ -2644,6 +2707,11 @@
public void resetSettingsLocked(int type, int userId, String packageName, int mode,
String tag) {
+ resetSettingsLocked(type, userId, packageName, mode, tag, null);
+ }
+
+ public void resetSettingsLocked(int type, int userId, String packageName, int mode,
+ String tag, @Nullable String prefix) {
final int key = makeKey(type, userId);
SettingsState settingsState = peekSettingsStateLocked(key);
if (settingsState == null) {
@@ -2656,7 +2724,8 @@
boolean someSettingChanged = false;
Setting setting = settingsState.getSettingLocked(name);
if (packageName.equals(setting.getPackageName())) {
- if (tag != null && !tag.equals(setting.getTag())) {
+ if ((tag != null && !tag.equals(setting.getTag()))
+ || (prefix != null && !setting.getName().startsWith(prefix))) {
continue;
}
if (settingsState.resetSettingLocked(name)) {
@@ -2676,6 +2745,9 @@
Setting setting = settingsState.getSettingLocked(name);
if (!SettingsState.isSystemPackage(getContext(),
setting.getPackageName())) {
+ if (prefix != null && !setting.getName().startsWith(prefix)) {
+ continue;
+ }
if (settingsState.resetSettingLocked(name)) {
someSettingChanged = true;
notifyForSettingsChange(key, name);
@@ -2693,6 +2765,9 @@
Setting setting = settingsState.getSettingLocked(name);
if (!SettingsState.isSystemPackage(getContext(),
setting.getPackageName())) {
+ if (prefix != null && !setting.getName().startsWith(prefix)) {
+ continue;
+ }
if (setting.isDefaultFromSystem()) {
if (settingsState.resetSettingLocked(name)) {
someSettingChanged = true;
@@ -2713,6 +2788,9 @@
for (String name : settingsState.getSettingNamesLocked()) {
Setting setting = settingsState.getSettingLocked(name);
boolean someSettingChanged = false;
+ if (prefix != null && !setting.getName().startsWith(prefix)) {
+ continue;
+ }
if (setting.isDefaultFromSystem()) {
if (settingsState.resetSettingLocked(name)) {
someSettingChanged = true;
diff --git a/packages/SettingsProvider/src/com/android/providers/settings/SettingsService.java b/packages/SettingsProvider/src/com/android/providers/settings/SettingsService.java
index 13537c4..36360a3 100644
--- a/packages/SettingsProvider/src/com/android/providers/settings/SettingsService.java
+++ b/packages/SettingsProvider/src/com/android/providers/settings/SettingsService.java
@@ -105,7 +105,7 @@
RESET,
}
- int mUser = -1; // unspecified
+ int mUser = UserHandle.USER_NULL;
CommandVerb mVerb = CommandVerb.UNSPECIFIED;
String mTable = null;
String mKey = null;
@@ -132,15 +132,15 @@
String arg = cmd;
do {
if ("--user".equals(arg)) {
- if (mUser != -1) {
- // --user specified more than once; invalid
+ if (mUser != UserHandle.USER_NULL) {
+ perr.println("Invalid user: --user specified more than once");
break;
}
- arg = getNextArgRequired();
- if ("current".equals(arg) || "cur".equals(arg)) {
- mUser = UserHandle.USER_CURRENT;
- } else {
- mUser = Integer.parseInt(arg);
+ mUser = UserHandle.parseUserArg(getNextArgRequired());
+
+ if (mUser == UserHandle.USER_ALL) {
+ perr.println("Invalid user: all");
+ return -1;
}
} else if (mVerb == CommandVerb.UNSPECIFIED) {
if ("get".equalsIgnoreCase(arg)) {
@@ -254,16 +254,13 @@
return -1;
}
- if (mUser == UserHandle.USER_CURRENT) {
+ if (mUser == UserHandle.USER_NULL || mUser == UserHandle.USER_CURRENT) {
try {
mUser = ActivityManager.getService().getCurrentUser().id;
} catch (RemoteException e) {
throw new RuntimeException("Failed in IPC", e);
}
}
- if (mUser < 0) {
- mUser = UserHandle.USER_SYSTEM;
- }
UserManager userManager = UserManager.get(mProvider.getContext());
if (userManager.getUserInfo(mUser) == null) {
perr.println("Invalid user: " + mUser);
@@ -312,8 +309,8 @@
try {
Bundle arg = new Bundle();
arg.putInt(Settings.CALL_METHOD_USER_KEY, userHandle);
- Bundle result =
- provider.call(resolveCallingPackage(), callListCommand, null, arg);
+ Bundle result = provider.call(resolveCallingPackage(), Settings.AUTHORITY,
+ callListCommand, null, arg);
lines.addAll(result.getStringArrayList(SettingsProvider.RESULT_SETTINGS_LIST));
Collections.sort(lines);
} catch (RemoteException e) {
@@ -337,7 +334,8 @@
try {
Bundle arg = new Bundle();
arg.putInt(Settings.CALL_METHOD_USER_KEY, userHandle);
- Bundle b = provider.call(resolveCallingPackage(), callGetCommand, key, arg);
+ Bundle b = provider.call(resolveCallingPackage(), Settings.AUTHORITY,
+ callGetCommand, key, arg);
if (b != null) {
result = b.getPairValue();
}
@@ -374,7 +372,8 @@
if (makeDefault) {
arg.putBoolean(Settings.CALL_METHOD_MAKE_DEFAULT_KEY, true);
}
- provider.call(resolveCallingPackage(), callPutCommand, key, arg);
+ provider.call(resolveCallingPackage(), Settings.AUTHORITY,
+ callPutCommand, key, arg);
} catch (RemoteException e) {
throw new RuntimeException("Failed in IPC", e);
}
@@ -397,8 +396,8 @@
try {
Bundle arg = new Bundle();
arg.putInt(Settings.CALL_METHOD_USER_KEY, userHandle);
- Bundle result =
- provider.call(resolveCallingPackage(), callDeleteCommand, key, arg);
+ Bundle result = provider.call(resolveCallingPackage(), Settings.AUTHORITY,
+ callDeleteCommand, key, arg);
return result.getInt(SettingsProvider.RESULT_ROWS_DELETED);
} catch (RemoteException e) {
throw new RuntimeException("Failed in IPC", e);
@@ -424,7 +423,7 @@
}
String packageName = mPackageName != null ? mPackageName : resolveCallingPackage();
arg.putInt(Settings.CALL_METHOD_USER_KEY, userHandle);
- provider.call(packageName, callResetCommand, null, arg);
+ provider.call(packageName, Settings.AUTHORITY, callResetCommand, null, arg);
} catch (RemoteException e) {
throw new RuntimeException("Failed in IPC", e);
}
diff --git a/packages/SettingsProvider/test/src/com/android/providers/settings/DeviceConfigServiceTest.java b/packages/SettingsProvider/test/src/com/android/providers/settings/DeviceConfigServiceTest.java
new file mode 100644
index 0000000..59de6a7e
--- /dev/null
+++ b/packages/SettingsProvider/test/src/com/android/providers/settings/DeviceConfigServiceTest.java
@@ -0,0 +1,236 @@
+/*
+ * 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.providers.settings;
+
+import static junit.framework.Assert.assertEquals;
+import static junit.framework.Assert.assertNull;
+
+import static org.junit.Assert.assertNotNull;
+
+import android.content.ContentResolver;
+import android.net.Uri;
+import android.os.Bundle;
+import android.provider.Settings;
+import android.support.test.InstrumentationRegistry;
+import android.support.test.runner.AndroidJUnit4;
+
+import libcore.io.Streams;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import java.io.FileInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+
+/**
+ * Tests for {@link DeviceConfigService}.
+ */
+@RunWith(AndroidJUnit4.class)
+public class DeviceConfigServiceTest {
+ /**
+ * TODO(b/113100523): Move this to DeviceConfig.java when it is added, and expose it as a System
+ * API.
+ */
+ private static final Uri CONFIG_CONTENT_URI =
+ Uri.parse("content://" + Settings.AUTHORITY + "/config");
+ private static final String sNamespace = "namespace1";
+ private static final String sKey = "key1";
+ private static final String sValue = "value1";
+
+ private ContentResolver mContentResolver;
+
+ @Before
+ public void setUp() {
+ mContentResolver = InstrumentationRegistry.getContext().getContentResolver();
+ }
+
+ @After
+ public void cleanUp() {
+ deleteFromContentProvider(mContentResolver, sNamespace, sKey);
+ }
+
+ @Test
+ public void testPut() throws Exception {
+ final String newNamespace = "namespace2";
+ final String newValue = "value2";
+
+ String result = getFromContentProvider(mContentResolver, sNamespace, sKey);
+ assertNull(result);
+
+ try {
+ executeShellCommand("device_config put " + sNamespace + " " + sKey + " " + sValue);
+ executeShellCommand("device_config put " + newNamespace + " " + sKey + " " + newValue);
+
+ result = getFromContentProvider(mContentResolver, sNamespace, sKey);
+ assertEquals(sValue, result);
+ result = getFromContentProvider(mContentResolver, newNamespace, sKey);
+ assertEquals(newValue, result);
+ } finally {
+ deleteFromContentProvider(mContentResolver, newNamespace, sKey);
+ }
+ }
+
+ @Test
+ public void testPut_invalidArgs() throws Exception {
+ // missing sNamespace
+ executeShellCommand("device_config put " + sKey + " " + sValue);
+ String result = getFromContentProvider(mContentResolver, sNamespace, sKey);
+ // still null
+ assertNull(result);
+
+ // too many arguments
+ executeShellCommand(
+ "device_config put " + sNamespace + " " + sKey + " " + sValue + " extra_arg");
+ result = getFromContentProvider(mContentResolver, sNamespace, sKey);
+ // still null
+ assertNull(result);
+ }
+
+ @Test
+ public void testDelete() throws Exception {
+ final String newNamespace = "namespace2";
+
+ putWithContentProvider(mContentResolver, sNamespace, sKey, sValue);
+ putWithContentProvider(mContentResolver, newNamespace, sKey, sValue);
+ String result = getFromContentProvider(mContentResolver, sNamespace, sKey);
+ assertEquals(sValue, result);
+ result = getFromContentProvider(mContentResolver, newNamespace, sKey);
+ assertEquals(sValue, result);
+
+ try {
+ executeShellCommand("device_config delete " + sNamespace + " " + sKey);
+ // sKey is deleted from sNamespace
+ result = getFromContentProvider(mContentResolver, sNamespace, sKey);
+ assertNull(result);
+ // sKey is not deleted from newNamespace
+ result = getFromContentProvider(mContentResolver, newNamespace, sKey);
+ assertEquals(sValue, result);
+ } finally {
+ deleteFromContentProvider(mContentResolver, newNamespace, sKey);
+ }
+ }
+
+ @Test
+ public void testDelete_invalidArgs() throws Exception {
+ putWithContentProvider(mContentResolver, sNamespace, sKey, sValue);
+ String result = getFromContentProvider(mContentResolver, sNamespace, sKey);
+ assertEquals(sValue, result);
+
+ // missing sNamespace
+ executeShellCommand("device_config delete " + sKey);
+ result = getFromContentProvider(mContentResolver, sNamespace, sKey);
+ // sValue was not deleted
+ assertEquals(sValue, result);
+
+ // too many arguments
+ executeShellCommand("device_config delete " + sNamespace + " " + sKey + " extra_arg");
+ result = getFromContentProvider(mContentResolver, sNamespace, sKey);
+ // sValue was not deleted
+ assertEquals(sValue, result);
+ }
+
+ @Test
+ public void testReset_setUntrustedDefault() throws Exception {
+ String newValue = "value2";
+
+ // make sValue the untrusted default (set by root)
+ executeShellCommand(
+ "device_config put " + sNamespace + " " + sKey + " " + sValue + " default");
+ // make newValue the current value
+ executeShellCommand(
+ "device_config put " + sNamespace + " " + sKey + " " + newValue);
+ String result = getFromContentProvider(mContentResolver, sNamespace, sKey);
+ assertEquals(newValue, result);
+
+ executeShellCommand("device_config reset untrusted_defaults " + sNamespace);
+ result = getFromContentProvider(mContentResolver, sNamespace, sKey);
+ // back to the default
+ assertEquals(sValue, result);
+
+ executeShellCommand("device_config reset trusted_defaults " + sNamespace);
+ result = getFromContentProvider(mContentResolver, sNamespace, sKey);
+ // not trusted default was set
+ assertNull(result);
+ }
+
+ @Test
+ public void testReset_setTrustedDefault() throws Exception {
+ String newValue = "value2";
+
+ // make sValue the trusted default (set by system)
+ putWithContentProvider(mContentResolver, sNamespace, sKey, sValue, true);
+ // make newValue the current value
+ executeShellCommand(
+ "device_config put " + sNamespace + " " + sKey + " " + newValue);
+ String result = getFromContentProvider(mContentResolver, sNamespace, sKey);
+ assertEquals(newValue, result);
+
+ executeShellCommand("device_config reset untrusted_defaults " + sNamespace);
+ result = getFromContentProvider(mContentResolver, sNamespace, sKey);
+ // back to the default
+ assertEquals(sValue, result);
+
+ executeShellCommand("device_config reset trusted_defaults " + sNamespace);
+ result = getFromContentProvider(mContentResolver, sNamespace, sKey);
+ // our trusted default is still set
+ assertEquals(sValue, result);
+ }
+
+ private static void executeShellCommand(String command) throws IOException {
+ InputStream is = new FileInputStream(InstrumentationRegistry.getInstrumentation()
+ .getUiAutomation().executeShellCommand(command).getFileDescriptor());
+ Streams.readFully(is);
+ }
+
+ private static void putWithContentProvider(ContentResolver resolver, String namespace,
+ String key, String value) {
+ putWithContentProvider(resolver, namespace, key, value, false);
+ }
+
+ private static void putWithContentProvider(ContentResolver resolver, String namespace,
+ String key, String value, boolean makeDefault) {
+ String compositeName = namespace + "/" + key;
+ Bundle args = new Bundle();
+ args.putString(Settings.NameValueTable.VALUE, value);
+ if (makeDefault) {
+ args.putBoolean(Settings.CALL_METHOD_MAKE_DEFAULT_KEY, true);
+ }
+ resolver.call(
+ CONFIG_CONTENT_URI, Settings.CALL_METHOD_PUT_CONFIG, compositeName, args);
+ }
+
+ private static String getFromContentProvider(ContentResolver resolver, String namespace,
+ String key) {
+ String compositeName = namespace + "/" + key;
+ Bundle result = resolver.call(
+ CONFIG_CONTENT_URI, Settings.CALL_METHOD_GET_CONFIG, compositeName, null);
+ assertNotNull(result);
+ return result.getString(Settings.NameValueTable.VALUE);
+ }
+
+ private static boolean deleteFromContentProvider(ContentResolver resolver, String namespace,
+ String key) {
+ String compositeName = namespace + "/" + key;
+ Bundle result = resolver.call(
+ CONFIG_CONTENT_URI, Settings.CALL_METHOD_DELETE_CONFIG, compositeName, null);
+ assertNotNull(result);
+ return compositeName.equals(result.getString(Settings.NameValueTable.VALUE));
+ }
+}
diff --git a/packages/Shell/AndroidManifest.xml b/packages/Shell/AndroidManifest.xml
index e564711..5fe08aa 100644
--- a/packages/Shell/AndroidManifest.xml
+++ b/packages/Shell/AndroidManifest.xml
@@ -51,6 +51,7 @@
<uses-permission android:name="android.permission.REAL_GET_TASKS" />
<uses-permission android:name="android.permission.CHANGE_CONFIGURATION" />
<uses-permission android:name="android.permission.REORDER_TASKS" />
+ <uses-permission android:name="android.permission.REMOVE_TASKS" />
<uses-permission android:name="android.permission.SET_ANIMATION_SCALE" />
<uses-permission android:name="android.permission.SET_PREFERRED_APPLICATIONS" />
<uses-permission android:name="android.permission.WRITE_SETTINGS" />
diff --git a/packages/SystemUI/plugin/src/com/android/systemui/plugins/ClockPlugin.java b/packages/SystemUI/plugin/src/com/android/systemui/plugins/ClockPlugin.java
index 7cb63ea..1a18f60 100644
--- a/packages/SystemUI/plugin/src/com/android/systemui/plugins/ClockPlugin.java
+++ b/packages/SystemUI/plugin/src/com/android/systemui/plugins/ClockPlugin.java
@@ -18,6 +18,8 @@
import com.android.systemui.plugins.annotations.ProvidesInterface;
+import java.util.TimeZone;
+
/**
* This plugin is used to replace main clock in keyguard.
*/
@@ -55,4 +57,9 @@
* @param darkAmount Amount of transition to doze: 1f for doze and 0f for awake.
*/
default void setDarkAmount(float darkAmount) {}
+
+ /**
+ * Notifies that the time zone has changed.
+ */
+ default void onTimeZoneChanged(TimeZone timeZone) {}
}
diff --git a/packages/SystemUI/res/values/dimens.xml b/packages/SystemUI/res/values/dimens.xml
index 8e0bfb6..b6c9b8c 100644
--- a/packages/SystemUI/res/values/dimens.xml
+++ b/packages/SystemUI/res/values/dimens.xml
@@ -23,6 +23,8 @@
<dimen name="navigation_bar_size">@*android:dimen/navigation_bar_height</dimen>
<!-- Minimum swipe distance to catch the swipe gestures to invoke assist or switch tasks. -->
<dimen name="navigation_bar_min_swipe_distance">48dp</dimen>
+ <!-- The distance from a side of device of the navigation bar to start an edge swipe -->
+ <dimen name="navigation_bar_edge_swipe_threshold">60dp</dimen>
<!-- thickness (height) of the dead zone at the top of the navigation bar,
reducing false presses on navbar buttons; approx 2mm -->
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardClockSwitch.java b/packages/SystemUI/src/com/android/keyguard/KeyguardClockSwitch.java
index b439c6c..0ec9014 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardClockSwitch.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardClockSwitch.java
@@ -17,6 +17,7 @@
import com.android.systemui.shared.plugins.PluginManager;
import java.util.Objects;
+import java.util.TimeZone;
/**
* Switch to show plugin clock when plugin is connected, otherwise it will show default clock.
@@ -162,6 +163,15 @@
}
/**
+ * Notifies that the time zone has changed.
+ */
+ public void onTimeZoneChanged(TimeZone timeZone) {
+ if (mClockPlugin != null) {
+ mClockPlugin.onTimeZoneChanged(timeZone);
+ }
+ }
+
+ /**
* When plugin changes, set all kept parameters into newer plugin.
*/
private void initPluginParams() {
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardPasswordView.java b/packages/SystemUI/src/com/android/keyguard/KeyguardPasswordView.java
index 6b24ad5..41afa9a 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardPasswordView.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardPasswordView.java
@@ -193,7 +193,8 @@
public void onClick(View v) {
mCallback.userActivity(); // Leave the screen on a bit longer
// Do not show auxiliary subtypes in password lock screen.
- mImm.showInputMethodPicker(false /* showAuxiliarySubtypes */);
+ mImm.showInputMethodPickerFromSystem(false /* showAuxiliarySubtypes */,
+ getContext().getDisplayId());
}
});
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardStatusView.java b/packages/SystemUI/src/com/android/keyguard/KeyguardStatusView.java
index be795d2..1e9d288 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardStatusView.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardStatusView.java
@@ -51,6 +51,7 @@
import com.google.android.collect.Sets;
import java.util.Locale;
+import java.util.TimeZone;
public class KeyguardStatusView extends GridLayout implements
ConfigurationController.ConfigurationListener, View.OnLayoutChangeListener {
@@ -85,6 +86,11 @@
}
@Override
+ public void onTimeZoneChanged(TimeZone timeZone) {
+ updateTimeZone(timeZone);
+ }
+
+ @Override
public void onKeyguardVisibilityChanged(boolean showing) {
if (showing) {
if (DEBUG) Slog.v(TAG, "refresh statusview showing:" + showing);
@@ -282,6 +288,10 @@
mClockView.refresh();
}
+ private void updateTimeZone(TimeZone timeZone) {
+ mClockView.onTimeZoneChanged(timeZone);
+ }
+
private void refreshFormat() {
Patterns.update(mContext);
mClockView.setFormat12Hour(Patterns.clockView12);
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java b/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java
index 904f9448..416441e 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java
@@ -98,6 +98,7 @@
import java.util.HashMap;
import java.util.List;
import java.util.Map.Entry;
+import java.util.TimeZone;
/**
* Watches for updates that may be interesting to the keyguard, and provides
@@ -151,6 +152,7 @@
private static final int MSG_BIOMETRIC_AUTHENTICATION_CONTINUE = 336;
private static final int MSG_DEVICE_POLICY_MANAGER_STATE_CHANGED = 337;
private static final int MSG_TELEPHONY_CAPABLE = 338;
+ private static final int MSG_TIMEZONE_UPDATE = 339;
/** Biometric authentication state: Not listening. */
private static final int BIOMETRIC_STATE_STOPPED = 0;
@@ -260,6 +262,9 @@
case MSG_TIME_UPDATE:
handleTimeUpdate();
break;
+ case MSG_TIMEZONE_UPDATE:
+ handleTimeZoneUpdate((String) msg.obj);
+ break;
case MSG_BATTERY_UPDATE:
handleBatteryUpdate((BatteryStatus) msg.obj);
break;
@@ -964,9 +969,12 @@
if (DEBUG) Log.d(TAG, "received broadcast " + action);
if (Intent.ACTION_TIME_TICK.equals(action)
- || Intent.ACTION_TIME_CHANGED.equals(action)
- || Intent.ACTION_TIMEZONE_CHANGED.equals(action)) {
+ || Intent.ACTION_TIME_CHANGED.equals(action)) {
mHandler.sendEmptyMessage(MSG_TIME_UPDATE);
+ } else if (Intent.ACTION_TIMEZONE_CHANGED.equals(action)) {
+ final Message msg = mHandler.obtainMessage(
+ MSG_TIMEZONE_UPDATE, intent.getStringExtra("time-zone"));
+ mHandler.sendMessage(msg);
} else if (Intent.ACTION_BATTERY_CHANGED.equals(action)) {
final int status = intent.getIntExtra(EXTRA_STATUS, BATTERY_STATUS_UNKNOWN);
final int plugged = intent.getIntExtra(EXTRA_PLUGGED, 0);
@@ -1860,6 +1868,21 @@
}
/**
+ * Handle (@line #MSG_TIMEZONE_UPDATE}
+ */
+ private void handleTimeZoneUpdate(String timeZone) {
+ if (DEBUG) Log.d(TAG, "handleTimeZoneUpdate");
+ for (int i = 0; i < mCallbacks.size(); i++) {
+ KeyguardUpdateMonitorCallback cb = mCallbacks.get(i).get();
+ if (cb != null) {
+ cb.onTimeZoneChanged(TimeZone.getTimeZone(timeZone));
+ // Also notify callbacks about time change to remain compatible.
+ cb.onTimeChanged();
+ }
+ }
+ }
+
+ /**
* Handle {@link #MSG_BATTERY_UPDATE}
*/
private void handleBatteryUpdate(BatteryStatus status) {
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitorCallback.java b/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitorCallback.java
index f818d05..8696bb7 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitorCallback.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitorCallback.java
@@ -26,6 +26,8 @@
import com.android.internal.telephony.IccCardConstants;
import com.android.systemui.statusbar.KeyguardIndicationController;
+import java.util.TimeZone;
+
/**
* Callback for general information relevant to lock screen.
*/
@@ -49,6 +51,13 @@
public void onTimeChanged() { }
/**
+ * Called when time zone changes.
+ *
+ * @note When time zone changes, onTimeChanged will be called too.
+ */
+ public void onTimeZoneChanged(TimeZone timeZone) { }
+
+ /**
* Called when the carrier PLMN or SPN changes.
*/
public void onRefreshCarrierInfo() { }
diff --git a/packages/SystemUI/src/com/android/systemui/pip/phone/PipMenuActivity.java b/packages/SystemUI/src/com/android/systemui/pip/phone/PipMenuActivity.java
index 8495fd3..86ce60d 100644
--- a/packages/SystemUI/src/com/android/systemui/pip/phone/PipMenuActivity.java
+++ b/packages/SystemUI/src/com/android/systemui/pip/phone/PipMenuActivity.java
@@ -224,6 +224,9 @@
// next tap
mTouchState.scheduleDoubleTapTimeoutCallback();
}
+ // Fall through
+ case MotionEvent.ACTION_CANCEL:
+ mTouchState.reset();
break;
}
return true;
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tileimpl/QSTileImpl.java b/packages/SystemUI/src/com/android/systemui/qs/tileimpl/QSTileImpl.java
index 451297b..cc27135 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tileimpl/QSTileImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tileimpl/QSTileImpl.java
@@ -17,9 +17,10 @@
import static com.android.internal.logging.nano.MetricsProto.MetricsEvent.ACTION_QS_CLICK;
import static com.android.internal.logging.nano.MetricsProto.MetricsEvent.ACTION_QS_LONG_PRESS;
import static com.android.internal.logging.nano.MetricsProto.MetricsEvent.ACTION_QS_SECONDARY_CLICK;
-import static com.android.internal.logging.nano.MetricsProto.MetricsEvent.FIELD_CONTEXT;
+import static com.android.internal.logging.nano.MetricsProto.MetricsEvent.FIELD_IS_FULL_QS;
import static com.android.internal.logging.nano.MetricsProto.MetricsEvent.FIELD_QS_POSITION;
import static com.android.internal.logging.nano.MetricsProto.MetricsEvent.FIELD_QS_VALUE;
+import static com.android.internal.logging.nano.MetricsProto.MetricsEvent.FIELD_STATUS_BAR_STATE;
import static com.android.internal.logging.nano.MetricsProto.MetricsEvent.TYPE_ACTION;
import static com.android.settingslib.RestrictedLockUtils.EnforcedAdmin;
@@ -52,6 +53,7 @@
import com.android.systemui.qs.PagedTileLayout.TilePage;
import com.android.systemui.qs.QSHost;
import com.android.systemui.qs.QuickStatusBarHeader;
+import com.android.systemui.statusbar.StatusBarStateController;
import java.util.ArrayList;
@@ -61,6 +63,8 @@
* State management done on a looper provided by the host. Tiles should update state in
* handleUpdateState. Callbacks affecting state should use refreshState to trigger another
* state update pass on tile looper.
+ *
+ * @param <TState> see above
*/
public abstract class QSTileImpl<TState extends State> implements QSTile {
protected final String TAG = "Tile." + getClass().getSimpleName();
@@ -76,6 +80,8 @@
protected final Handler mUiHandler = new Handler(Looper.getMainLooper());
private final ArraySet<Object> mListeners = new ArraySet<>();
private final MetricsLogger mMetricsLogger = Dependency.get(MetricsLogger.class);
+ private final StatusBarStateController
+ mStatusBarStateController = Dependency.get(StatusBarStateController.class);
private final ArrayList<Callback> mCallbacks = new ArrayList<>();
private final Object mStaleListener = new Object();
@@ -172,17 +178,23 @@
}
public void click() {
- mMetricsLogger.write(populate(new LogMaker(ACTION_QS_CLICK).setType(TYPE_ACTION)));
+ mMetricsLogger.write(populate(new LogMaker(ACTION_QS_CLICK).setType(TYPE_ACTION)
+ .addTaggedData(FIELD_STATUS_BAR_STATE,
+ mStatusBarStateController.getState())));
mHandler.sendEmptyMessage(H.CLICK);
}
public void secondaryClick() {
- mMetricsLogger.write(populate(new LogMaker(ACTION_QS_SECONDARY_CLICK).setType(TYPE_ACTION)));
+ mMetricsLogger.write(populate(new LogMaker(ACTION_QS_SECONDARY_CLICK).setType(TYPE_ACTION)
+ .addTaggedData(FIELD_STATUS_BAR_STATE,
+ mStatusBarStateController.getState())));
mHandler.sendEmptyMessage(H.SECONDARY_CLICK);
}
public void longClick() {
- mMetricsLogger.write(populate(new LogMaker(ACTION_QS_LONG_PRESS).setType(TYPE_ACTION)));
+ mMetricsLogger.write(populate(new LogMaker(ACTION_QS_LONG_PRESS).setType(TYPE_ACTION)
+ .addTaggedData(FIELD_STATUS_BAR_STATE,
+ mStatusBarStateController.getState())));
mHandler.sendEmptyMessage(H.LONG_CLICK);
Prefs.putInt(
@@ -196,7 +208,7 @@
logMaker.addTaggedData(FIELD_QS_VALUE, ((BooleanState) mState).value ? 1 : 0);
}
return logMaker.setSubtype(getMetricsCategory())
- .addTaggedData(FIELD_CONTEXT, mIsFullQs)
+ .addTaggedData(FIELD_IS_FULL_QS, mIsFullQs)
.addTaggedData(FIELD_QS_POSITION, mHost.indexOf(mTileSpec));
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationPresenter.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationPresenter.java
index 3334f8b..a5c0a2d 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationPresenter.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationPresenter.java
@@ -67,7 +67,7 @@
/**
* True if the presenter is currently locked.
*/
- default boolean isPresenterLocked() { return false; }
+ boolean isPresenterLocked();
/**
* Called when the row states are updated by {@link NotificationViewHierarchyManager}.
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationData.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationData.java
index 3f8583c..d9fe982 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationData.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationData.java
@@ -815,9 +815,18 @@
public boolean isHighPriority(StatusBarNotification statusBarNotification) {
if (mRankingMap != null) {
getRanking(statusBarNotification.getKey(), mTmpRanking);
- return mTmpRanking.getImportance() >= NotificationManager.IMPORTANCE_DEFAULT
+ if (mTmpRanking.getImportance() >= NotificationManager.IMPORTANCE_DEFAULT
|| statusBarNotification.getNotification().isForegroundService()
- || statusBarNotification.getNotification().hasMediaSession();
+ || statusBarNotification.getNotification().hasMediaSession()) {
+ return true;
+ }
+ if (mGroupManager.isSummaryOfGroup(statusBarNotification)) {
+ for (Entry child : mGroupManager.getLogicalChildren(statusBarNotification)) {
+ if (isHighPriority(child.notification)) {
+ return true;
+ }
+ }
+ }
}
return false;
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationMenuRow.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationMenuRow.java
index 50564e3..d97162c 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationMenuRow.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationMenuRow.java
@@ -30,6 +30,7 @@
import android.os.Handler;
import android.os.Looper;
import android.service.notification.StatusBarNotification;
+import android.util.ArrayMap;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
@@ -47,6 +48,7 @@
import java.util.ArrayList;
import java.util.List;
+import java.util.Map;
public class NotificationMenuRow implements NotificationMenuRowPlugin, View.OnClickListener,
ExpandableNotificationRow.LayoutListener {
@@ -74,6 +76,7 @@
private MenuItem mSnoozeItem;
private ArrayList<MenuItem> mLeftMenuItems;
private ArrayList<MenuItem> mRightMenuItems;
+ private final Map<View, MenuItem> mMenuItemsByView = new ArrayMap<>();
private OnMenuEventListener mMenuListener;
private ValueAnimator mFadeAnimator;
@@ -287,6 +290,7 @@
private void populateMenuViews() {
if (mMenuContainer != null) {
mMenuContainer.removeAllViews();
+ mMenuItemsByView.clear();
} else {
mMenuContainer = new FrameLayout(mContext);
}
@@ -486,10 +490,8 @@
final int centerY = v.getHeight() / 2;
final int x = mIconLocation[0] - mParentLocation[0] + centerX;
final int y = mIconLocation[1] - mParentLocation[1] + centerY;
- final int index = mMenuContainer.indexOfChild(v);
- if (mMenuListener != null) {
- mMenuListener.onMenuClicked(mParent, x, y,
- (mOnLeft ? mLeftMenuItems : mRightMenuItems).get(index));
+ if (mMenuItemsByView.containsKey(v)) {
+ mMenuListener.onMenuClicked(mParent, x, y, mMenuItemsByView.get(v));
}
}
@@ -641,8 +643,8 @@
NotificationInfo infoContent = (NotificationInfo) LayoutInflater.from(context).inflate(
R.layout.notification_info, null, false);
int iconResId = isCurrentlySilent
- ? R.drawable.ic_notifications_alert
- : R.drawable.ic_notifications_silence;
+ ? R.drawable.ic_notifications_silence
+ : R.drawable.ic_notifications_alert;
return new NotificationMenuItem(context, infoDescription, infoContent, iconResId);
}
@@ -665,6 +667,7 @@
lp.height = mHorizSpaceForIcon;
menuView.setLayoutParams(lp);
}
+ mMenuItemsByView.put(menuView, item);
}
@VisibleForTesting
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBackAction.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBackAction.java
index b83ebc7..9c8b1b1 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBackAction.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBackAction.java
@@ -56,6 +56,11 @@
}
@Override
+ public boolean allowHitTargetToMoveOverDrag() {
+ return true;
+ }
+
+ @Override
public boolean canPerformAction() {
return mProxySender.getBackButtonAlpha() > 0;
}
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 cd6e1d7..30e8409 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarView.java
@@ -63,6 +63,7 @@
import android.view.inputmethod.InputMethodManager;
import android.widget.FrameLayout;
+import com.android.internal.annotations.VisibleForTesting;
import com.android.systemui.Dependency;
import com.android.systemui.DockedStackExistsListener;
import com.android.systemui.Interpolators;
@@ -96,7 +97,6 @@
final static boolean ALTERNATE_CAR_MODE_UI = false;
- final Display mDisplay;
View mCurrentView = null;
View[] mRotatedViews = new View[4];
@@ -154,6 +154,7 @@
private QuickScrubAction mQuickScrubAction;
private QuickStepAction mQuickStepAction;
private NavigationBackAction mBackAction;
+ private QuickSwitchAction mQuickSwitchAction;
/**
* Helper that is responsible for showing the right toast when a disallowed activity operation
@@ -212,8 +213,8 @@
private final OnClickListener mImeSwitcherClickListener = new OnClickListener() {
@Override
public void onClick(View view) {
- mContext.getSystemService(InputMethodManager.class)
- .showInputMethodPicker(true /* showAuxiliarySubtypes */);
+ mContext.getSystemService(InputMethodManager.class).showInputMethodPickerFromSystem(
+ true /* showAuxiliarySubtypes */, getContext().getDisplayId());
}
};
@@ -281,8 +282,6 @@
public NavigationBarView(Context context, AttributeSet attrs) {
super(context, attrs);
- mDisplay = context.getDisplay();
-
mVertical = false;
mLongClickableAccessibilityButton = false;
@@ -326,9 +325,10 @@
mQuickScrubAction = new QuickScrubAction(this, mOverviewProxyService);
mQuickStepAction = new QuickStepAction(this, mOverviewProxyService);
mBackAction = new NavigationBackAction(this, mOverviewProxyService);
+ mQuickSwitchAction = new QuickSwitchAction(this, mOverviewProxyService);
mDefaultGestureMap = new NavigationGestureAction[] {
mQuickStepAction, null /* swipeDownAction*/, null /* swipeLeftAction */,
- mQuickScrubAction
+ mQuickScrubAction, null /* swipeLeftEdgeAction */, null /* swipeRightEdgeAction */
};
mPrototypeController = new NavigationPrototypeController(mHandler, mContext);
@@ -359,7 +359,9 @@
getNavigationActionFromType(assignedMap[0], mDefaultGestureMap[0]),
getNavigationActionFromType(assignedMap[1], mDefaultGestureMap[1]),
getNavigationActionFromType(assignedMap[2], mDefaultGestureMap[2]),
- getNavigationActionFromType(assignedMap[3], mDefaultGestureMap[3]));
+ getNavigationActionFromType(assignedMap[3], mDefaultGestureMap[3]),
+ getNavigationActionFromType(assignedMap[4], mDefaultGestureMap[4]),
+ getNavigationActionFromType(assignedMap[5], mDefaultGestureMap[5]));
}
}
@@ -372,6 +374,8 @@
return mQuickScrubAction;
case NavigationPrototypeController.ACTION_BACK:
return mBackAction;
+ case NavigationPrototypeController.ACTION_QUICKSWITCH:
+ return mQuickSwitchAction;
default:
return defaultAction;
}
@@ -652,8 +656,8 @@
Log.i(TAG, "updateNavButtonIcons (b/113914868): home disabled=" + disableHome
+ " mDisabledFlags=" + mDisabledFlags);
- // Always disable recents when alternate car mode UI is active.
- boolean disableRecent = mUseCarModeUi || !isOverviewEnabled();
+ // Always disable recents when alternate car mode UI is active and for secondary displays.
+ boolean disableRecent = isRecentsButtonDisabled();
boolean disableBack = QuickStepController.shouldhideBackButton(getContext())
|| (((mDisabledFlags & View.STATUS_BAR_DISABLE_BACK) != 0) && !useAltBack);
@@ -689,6 +693,16 @@
getRecentsButton().setVisibility(disableRecent ? View.INVISIBLE : View.VISIBLE);
}
+ @VisibleForTesting
+ boolean isRecentsButtonDisabled() {
+ return mUseCarModeUi || !isOverviewEnabled()
+ || getContext().getDisplayId() != Display.DEFAULT_DISPLAY;
+ }
+
+ private Display getContextDisplay() {
+ return getContext().getDisplay();
+ }
+
public boolean inScreenPinning() {
return ActivityManagerWrapper.getInstance().isScreenPinningActive();
}
@@ -890,7 +904,7 @@
}
private void updateCurrentView() {
- final int rot = mDisplay.getRotation();
+ final int rot = getContextDisplay().getRotation();
for (int i=0; i<4; i++) {
mRotatedViews[i].setVisibility(View.GONE);
}
@@ -954,7 +968,7 @@
int navBarPos = NAV_BAR_INVALID;
try {
navBarPos = WindowManagerGlobal.getWindowManagerService().getNavBarPosition(
- mDisplay.getDisplayId());
+ getContext().getDisplayId());
} catch (RemoteException e) {
Slog.e(TAG, "Failed to get nav bar position.", e);
}
@@ -1128,7 +1142,7 @@
pw.println("NavigationBarView {");
final Rect r = new Rect();
final Point size = new Point();
- mDisplay.getRealSize(size);
+ getContextDisplay().getRealSize(size);
pw.println(String.format(" this: " + StatusBar.viewInfo(this)
+ " " + visibilityToString(getVisibility())));
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationGestureAction.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationGestureAction.java
index a8d00c4..8c57fc3 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationGestureAction.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationGestureAction.java
@@ -112,7 +112,7 @@
/**
* @return whether or not to move the button that started gesture over with user input drag
*/
- public boolean requiresDragWithHitTarget() {
+ public boolean allowHitTargetToMoveOverDrag() {
return false;
}
@@ -139,9 +139,9 @@
* Tell if action is enabled. Compared to {@link #canPerformAction()} this is based on settings
* if the action is disabled for a particular gesture. For example a back action can be enabled
* however if there is nothing to back to then {@link #canPerformAction()} should return false.
- * In this way if the action requires {@link #requiresDragWithHitTarget()} then if enabled, the
- * button can be dragged with a large dampening factor during the gesture but will not activate
- * the action.
+ * In this way if the action requires {@link #allowHitTargetToMoveOverDrag()} then if enabled,
+ * the button can be dragged with a large dampening factor during the gesture but will not
+ * activate the action.
* @return true if this action is enabled and can run
*/
public abstract boolean isEnabled();
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationPrototypeController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationPrototypeController.java
index e8c0bf1..b11b6d4 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationPrototypeController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationPrototypeController.java
@@ -24,7 +24,6 @@
import android.provider.Settings;
import android.provider.Settings.SettingNotFoundException;
-import android.util.Log;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
@@ -46,6 +45,7 @@
static final int ACTION_QUICKSTEP = 1;
static final int ACTION_QUICKSCRUB = 2;
static final int ACTION_BACK = 3;
+ static final int ACTION_QUICKSWITCH = 4;
private OnPrototypeChangedListener mListener;
@@ -53,7 +53,7 @@
* Each index corresponds to a different action set in QuickStepController
* {@see updateSwipeLTRBackSetting}
*/
- private int[] mActionMap = new int[4];
+ private int[] mActionMap = new int[6];
private final Context mContext;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/QuickScrubAction.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/QuickScrubAction.java
index 2b202eb..bbfd51a 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/QuickScrubAction.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/QuickScrubAction.java
@@ -18,8 +18,6 @@
import static com.android.systemui.Interpolators.ALPHA_IN;
import static com.android.systemui.Interpolators.ALPHA_OUT;
-import static com.android.systemui.recents.OverviewProxyService.DEBUG_OVERVIEW_PROXY;
-import static com.android.systemui.recents.OverviewProxyService.TAG_OPS;
import android.animation.Animator;
import android.animation.AnimatorListenerAdapter;
@@ -31,11 +29,8 @@
import android.graphics.Canvas;
import android.graphics.Paint;
import android.graphics.RadialGradient;
-import android.graphics.Rect;
import android.graphics.Shader;
-import android.os.RemoteException;
import android.util.FloatProperty;
-import android.util.Log;
import android.view.MotionEvent;
import android.view.View;
@@ -46,7 +41,7 @@
/**
* QuickScrub action to send to launcher to start quickscrub gesture
*/
-public class QuickScrubAction extends NavigationGestureAction {
+public class QuickScrubAction extends QuickSwitchAction {
private static final String TAG = "QuickScrubAction";
private static final float TRACK_SCALE = 0.95f;
@@ -65,7 +60,6 @@
private final int mTrackThickness;
private final int mTrackEndPadding;
private final Paint mTrackPaint = new Paint();
- private final Rect mTrackRect = new Rect();
private final FloatProperty<QuickScrubAction> mTrackAlphaProperty =
new FloatProperty<QuickScrubAction>("TrackAlpha") {
@@ -177,7 +171,7 @@
x1 = mNavigationBarView.getPaddingStart() + mTrackEndPadding;
x2 = x1 + width - 2 * mTrackEndPadding;
}
- mTrackRect.set(x1, y1, x2, y2);
+ mDragOverRect.set(x1, y1, x2, y2);
}
@Override
@@ -194,15 +188,16 @@
mTrackPaint.setAlpha(Math.round(255f * mTrackAlpha));
// Scale the track, but apply the inverse scale from the nav bar
- final float radius = mTrackRect.height() / 2;
+ final float radius = mDragOverRect.height() / 2;
canvas.save();
- float translate = Utilities.clamp(mHighlightCenter, mTrackRect.left, mTrackRect.right);
+ float translate = Utilities.clamp(mHighlightCenter, mDragOverRect.left,
+ mDragOverRect.right);
canvas.translate(translate, 0);
canvas.scale(mTrackScale / mNavigationBarView.getScaleX(),
1f / mNavigationBarView.getScaleY(),
- mTrackRect.centerX(), mTrackRect.centerY());
- canvas.drawRoundRect(mTrackRect.left - translate, mTrackRect.top,
- mTrackRect.right - translate, mTrackRect.bottom, radius, radius, mTrackPaint);
+ mDragOverRect.centerX(), mDragOverRect.centerY());
+ canvas.drawRoundRect(mDragOverRect.left - translate, mDragOverRect.top,
+ mDragOverRect.right - translate, mDragOverRect.bottom, radius, radius, mTrackPaint);
canvas.restore();
}
@@ -212,11 +207,6 @@
}
@Override
- public boolean disableProxyEvents() {
- return true;
- }
-
- @Override
protected void onGestureStart(MotionEvent event) {
updateHighlight();
ObjectAnimator trackAnimator = ObjectAnimator.ofPropertyValuesHolder(this,
@@ -231,42 +221,12 @@
mTrackAnimator.playTogether(trackAnimator, navBarAnimator);
mTrackAnimator.start();
- // Disable slippery for quick scrub to not cancel outside the nav bar
- mNavigationBarView.updateSlippery();
-
- try {
- mProxySender.getProxy().onQuickScrubStart();
- if (DEBUG_OVERVIEW_PROXY) {
- Log.d(TAG_OPS, "Quick Scrub Start");
- }
- } catch (RemoteException e) {
- Log.e(TAG, "Failed to send start of quick scrub.", e);
- }
- mProxySender.notifyQuickScrubStarted();
+ startQuickGesture(event);
}
@Override
public void onGestureMove(int x, int y) {
- int trackSize, offset;
- if (isNavBarVertical()) {
- trackSize = mTrackRect.height();
- offset = y - mTrackRect.top;
- } else {
- offset = x - mTrackRect.left;
- trackSize = mTrackRect.width();
- }
- if (!mDragHorizontalPositive || !mDragVerticalPositive) {
- offset -= isNavBarVertical() ? mTrackRect.height() : mTrackRect.width();
- }
- float scrubFraction = Utilities.clamp(Math.abs(offset) * 1f / trackSize, 0, 1);
- try {
- mProxySender.getProxy().onQuickScrubProgress(scrubFraction);
- if (DEBUG_OVERVIEW_PROXY) {
- Log.d(TAG_OPS, "Quick Scrub Progress:" + scrubFraction);
- }
- } catch (RemoteException e) {
- Log.e(TAG, "Failed to send progress of quick scrub.", e);
- }
+ super.onGestureMove(x, y);
mHighlightCenter = x;
mNavigationBarView.invalidate();
}
@@ -278,14 +238,7 @@
private void endQuickScrub(boolean animate) {
animateEnd();
- try {
- mProxySender.getProxy().onQuickScrubEnd();
- if (DEBUG_OVERVIEW_PROXY) {
- Log.d(TAG_OPS, "Quick Scrub End");
- }
- } catch (RemoteException e) {
- Log.e(TAG, "Failed to send end of quick scrub.", e);
- }
+ endQuickGesture(animate);
if (!animate) {
if (mTrackAnimator != null) {
mTrackAnimator.end();
@@ -295,7 +248,7 @@
}
private void updateHighlight() {
- if (mTrackRect.isEmpty()) {
+ if (mDragOverRect.isEmpty()) {
return;
}
int colorBase, colorGrad;
@@ -306,8 +259,8 @@
colorBase = getContext().getColor(R.color.quick_step_track_background_background_light);
colorGrad = getContext().getColor(R.color.quick_step_track_background_foreground_light);
}
- final RadialGradient mHighlight = new RadialGradient(0, mTrackRect.height() / 2,
- mTrackRect.width() * GRADIENT_WIDTH, colorGrad, colorBase,
+ final RadialGradient mHighlight = new RadialGradient(0, mDragOverRect.height() / 2,
+ mDragOverRect.width() * GRADIENT_WIDTH, colorGrad, colorBase,
Shader.TileMode.CLAMP);
mTrackPaint.setShader(mHighlight);
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/QuickStepController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/QuickStepController.java
index 4983618..9eb5737a 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/QuickStepController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/QuickStepController.java
@@ -76,7 +76,9 @@
private static final int ACTION_SWIPE_DOWN_INDEX = 1;
private static final int ACTION_SWIPE_LEFT_INDEX = 2;
private static final int ACTION_SWIPE_RIGHT_INDEX = 3;
- private static final int MAX_GESTURES = 4;
+ private static final int ACTION_SWIPE_LEFT_FROM_EDGE_INDEX = 4;
+ private static final int ACTION_SWIPE_RIGHT_FROM_EDGE_INDEX = 5;
+ private static final int MAX_GESTURES = 6;
private NavigationBarView mNavigationBarView;
@@ -97,6 +99,7 @@
private float mMaxDragLimit;
private float mMinDragLimit;
private float mDragDampeningFactor;
+ private float mEdgeSwipeThreshold;
private NavigationGestureAction mCurrentAction;
private NavigationGestureAction[] mGestureActions = new NavigationGestureAction[MAX_GESTURES];
@@ -128,15 +131,21 @@
* @param swipeDownAction action after swiping down
* @param swipeLeftAction action after swiping left
* @param swipeRightAction action after swiping right
+ * @param swipeLeftFromEdgeAction action swiping left starting from the right side
+ * @param swipeRightFromEdgeAction action swiping right starting from the left side
*/
public void setGestureActions(@Nullable NavigationGestureAction swipeUpAction,
@Nullable NavigationGestureAction swipeDownAction,
@Nullable NavigationGestureAction swipeLeftAction,
- @Nullable NavigationGestureAction swipeRightAction) {
+ @Nullable NavigationGestureAction swipeRightAction,
+ @Nullable NavigationGestureAction swipeLeftFromEdgeAction,
+ @Nullable NavigationGestureAction swipeRightFromEdgeAction) {
mGestureActions[ACTION_SWIPE_UP_INDEX] = swipeUpAction;
mGestureActions[ACTION_SWIPE_DOWN_INDEX] = swipeDownAction;
mGestureActions[ACTION_SWIPE_LEFT_INDEX] = swipeLeftAction;
mGestureActions[ACTION_SWIPE_RIGHT_INDEX] = swipeRightAction;
+ mGestureActions[ACTION_SWIPE_LEFT_FROM_EDGE_INDEX] = swipeLeftFromEdgeAction;
+ mGestureActions[ACTION_SWIPE_RIGHT_FROM_EDGE_INDEX] = swipeRightFromEdgeAction;
// Set the current state to all actions
for (NavigationGestureAction action: mGestureActions) {
@@ -233,6 +242,8 @@
mNavigationBarView.transformMatrixToLocal(mTransformLocalMatrix);
mAllowGestureDetection = true;
mNotificationsVisibleOnDown = !mNavigationBarView.isNotificationsFullyCollapsed();
+ mEdgeSwipeThreshold = mContext.getResources()
+ .getDimensionPixelSize(R.dimen.navigation_bar_edge_swipe_threshold);
break;
}
case MotionEvent.ACTION_MOVE: {
@@ -284,13 +295,17 @@
}
} else if (exceededSwipeHorizontalTouchSlop) {
if (mDragHPositive ? (posH < touchDownH) : (posH > touchDownH)) {
- // Swiping left (ltr) gesture
- tryToStartGesture(mGestureActions[ACTION_SWIPE_LEFT_INDEX],
- true /* alignedWithNavBar */, event);
+ // Swiping left (rtl) gesture
+ int index = isEdgeSwipeAlongNavBar(touchDownH, !mDragHPositive)
+ ? ACTION_SWIPE_LEFT_FROM_EDGE_INDEX : ACTION_SWIPE_LEFT_INDEX;
+ tryToStartGesture(mGestureActions[index], true /* alignedWithNavBar */,
+ event);
} else {
// Swiping right (ltr) gesture
- tryToStartGesture(mGestureActions[ACTION_SWIPE_RIGHT_INDEX],
- true /* alignedWithNavBar */, event);
+ int index = isEdgeSwipeAlongNavBar(touchDownH, mDragHPositive)
+ ? ACTION_SWIPE_RIGHT_FROM_EDGE_INDEX : ACTION_SWIPE_RIGHT_INDEX;
+ tryToStartGesture(mGestureActions[index], true /* alignedWithNavBar */,
+ event);
}
}
}
@@ -333,6 +348,17 @@
return mCurrentAction != null || deadZoneConsumed;
}
+ private boolean isEdgeSwipeAlongNavBar(int touchDown, boolean dragPositiveDirection) {
+ // Detect edge swipe from side of 0 -> threshold
+ if (dragPositiveDirection) {
+ return touchDown < mEdgeSwipeThreshold;
+ }
+ // Detect edge swipe from side of size -> (size - threshold)
+ final int largeSide = isNavBarVertical()
+ ? mNavigationBarView.getHeight() : mNavigationBarView.getWidth();
+ return touchDown > largeSide - mEdgeSwipeThreshold;
+ }
+
private void handleDragHitTarget(int position, int touchDown) {
// Drag the hit target if gesture action requires it
if (mHitTarget != null && (mGestureVerticalDragsButton || mGestureHorizontalDragsButton)) {
@@ -480,7 +506,7 @@
event.transform(mTransformLocalMatrix);
// Calculate the bounding limits of drag to avoid dragging off nav bar's window
- if (action.requiresDragWithHitTarget() && mHitTarget != null) {
+ if (action.allowHitTargetToMoveOverDrag() && mHitTarget != null) {
final int[] buttonCenter = new int[2];
View button = mHitTarget.getCurrentView();
button.getLocationInWindow(buttonCenter);
@@ -505,7 +531,7 @@
// Handle direction of the hit target drag from the axis that started the gesture
// Also calculate the dampening factor, weaker dampening if there is an active action
- if (action.requiresDragWithHitTarget()) {
+ if (action.allowHitTargetToMoveOverDrag()) {
if (alignedWithNavBar) {
mGestureHorizontalDragsButton = true;
mGestureVerticalDragsButton = false;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/QuickSwitchAction.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/QuickSwitchAction.java
new file mode 100644
index 0000000..40f2392
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/QuickSwitchAction.java
@@ -0,0 +1,139 @@
+/*
+ * 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.statusbar.phone;
+
+import static com.android.systemui.recents.OverviewProxyService.DEBUG_OVERVIEW_PROXY;
+import static com.android.systemui.recents.OverviewProxyService.TAG_OPS;
+
+import android.annotation.NonNull;
+import android.graphics.Rect;
+import android.os.RemoteException;
+import android.provider.Settings;
+import android.util.Log;
+import android.view.MotionEvent;
+
+import com.android.systemui.recents.OverviewProxyService;
+import com.android.systemui.shared.recents.utilities.Utilities;
+
+/**
+ * QuickSwitch action to send to launcher
+ */
+public class QuickSwitchAction extends NavigationGestureAction {
+ private static final String TAG = "QuickSwitchAction";
+ private static final String QUICKSWITCH_ENABLED_SETTING = "QUICK_SWITCH";
+
+ protected final Rect mDragOverRect = new Rect();
+
+ public QuickSwitchAction(@NonNull NavigationBarView navigationBar,
+ @NonNull OverviewProxyService service) {
+ super(navigationBar, service);
+ }
+
+ @Override
+ public void setBarState(boolean changed, int navBarPos, boolean dragHorPositive,
+ boolean dragVerPositive) {
+ super.setBarState(changed, navBarPos, dragHorPositive, dragVerPositive);
+ if (changed && isActive()) {
+ // End quickscrub if the state changes mid-transition
+ endQuickGesture(false /* animate */);
+ }
+ }
+
+ @Override
+ public boolean isEnabled() {
+ return mNavigationBarView.isQuickScrubEnabled();
+ }
+
+ @Override
+ protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
+ super.onLayout(changed, left, top, right, bottom);
+ mDragOverRect.set(top, left, right, bottom);
+ }
+
+ @Override
+ public boolean disableProxyEvents() {
+ return true;
+ }
+
+ @Override
+ protected void onGestureStart(MotionEvent event) {
+ // Temporarily enable launcher to allow quick switch instead of quick scrub
+ Settings.Global.putInt(mNavigationBarView.getContext().getContentResolver(),
+ QUICKSWITCH_ENABLED_SETTING, 1 /* enabled */);
+
+ startQuickGesture(event);
+ }
+
+ @Override
+ public void onGestureMove(int x, int y) {
+ int dragLength, offset;
+ if (isNavBarVertical()) {
+ dragLength = mDragOverRect.height();
+ offset = y - mDragOverRect.top;
+ } else {
+ offset = x - mDragOverRect.left;
+ dragLength = mDragOverRect.width();
+ }
+ if (!mDragHorizontalPositive || !mDragVerticalPositive) {
+ offset -= dragLength;
+ }
+ float scrubFraction = Utilities.clamp(Math.abs(offset) * 1f / dragLength, 0, 1);
+ try {
+ mProxySender.getProxy().onQuickScrubProgress(scrubFraction);
+ if (DEBUG_OVERVIEW_PROXY) {
+ Log.d(TAG_OPS, "Quick Switch Progress:" + scrubFraction);
+ }
+ } catch (RemoteException e) {
+ Log.e(TAG, "Failed to send progress of quick switch.", e);
+ }
+ }
+
+ @Override
+ protected void onGestureEnd() {
+ endQuickGesture(true /* animate */);
+
+ // Disable launcher to use quick switch instead of quick scrub
+ Settings.Global.putInt(mNavigationBarView.getContext().getContentResolver(),
+ QUICKSWITCH_ENABLED_SETTING, 0 /* disabled */);
+ }
+
+ protected void startQuickGesture(MotionEvent event) {
+ // Disable slippery for quick scrub to not cancel outside the nav bar
+ mNavigationBarView.updateSlippery();
+
+ try {
+ mProxySender.getProxy().onQuickScrubStart();
+ if (DEBUG_OVERVIEW_PROXY) {
+ Log.d(TAG_OPS, "Quick Scrub Start");
+ }
+ } catch (RemoteException e) {
+ Log.e(TAG, "Failed to send start of quick scrub.", e);
+ }
+ mProxySender.notifyQuickScrubStarted();
+ }
+
+ protected void endQuickGesture(boolean animate) {
+ try {
+ mProxySender.getProxy().onQuickScrubEnd();
+ if (DEBUG_OVERVIEW_PROXY) {
+ Log.d(TAG_OPS, "Quick Scrub End");
+ }
+ } catch (RemoteException e) {
+ Log.e(TAG, "Failed to send end of quick scrub.", e);
+ }
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java
index bf53b77..b351f1d 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java
@@ -1023,7 +1023,7 @@
mPresenter = new StatusBarNotificationPresenter(mContext, mNotificationPanel,
mHeadsUpManager, mStatusBarWindow, mStackScroller, mDozeScrimController,
- mScrimController, mActivityLaunchAnimator);
+ mScrimController, mActivityLaunchAnimator, mStatusBarKeyguardViewManager);
mAppOpsController.addCallback(APP_OPS, this);
mNotificationListener.setUpWithPresenter(mPresenter);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarNotificationPresenter.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarNotificationPresenter.java
index 3550bd6..d99af1f 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarNotificationPresenter.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarNotificationPresenter.java
@@ -97,6 +97,7 @@
private final AccessibilityManager mAccessibilityManager;
private final KeyguardManager mKeyguardManager;
private final ActivityLaunchAnimator mActivityLaunchAnimator;
+ private final StatusBarKeyguardViewManager mStatusBarKeyguardViewManager;
private final int mMaxAllowedKeyguardNotifications;
private final IStatusBarService mBarService;
private boolean mReinflateNotificationsOnUserSwitched;
@@ -113,13 +114,15 @@
ViewGroup stackScroller,
DozeScrimController dozeScrimController,
ScrimController scrimController,
- ActivityLaunchAnimator activityLaunchAnimator) {
+ ActivityLaunchAnimator activityLaunchAnimator,
+ StatusBarKeyguardViewManager statusBarKeyguardViewManager) {
mContext = context;
mNotificationPanel = panel;
mHeadsUpManager = headsUp;
mCommandQueue = getComponent(context, CommandQueue.class);
mAboveShelfObserver = new AboveShelfObserver(stackScroller);
mActivityLaunchAnimator = activityLaunchAnimator;
+ mStatusBarKeyguardViewManager = statusBarKeyguardViewManager;
mAboveShelfObserver.setListener(statusBarWindow.findViewById(
R.id.notification_container_parent));
mAccessibilityManager = context.getSystemService(AccessibilityManager.class);
@@ -367,6 +370,12 @@
return mVrMode;
}
+ @Override
+ public boolean isPresenterLocked() {
+ return mStatusBarKeyguardViewManager.isShowing()
+ && mStatusBarKeyguardViewManager.isSecure();
+ }
+
private void onLockedNotificationImportanceChange(OnDismissAction dismissAction) {
mStatusBarStateController.setLeaveOpenOnKeyguardHide(true);
mActivityStarter.dismissKeyguardThenExecute(dismissAction, null,
diff --git a/packages/SystemUI/tests/src/com/android/systemui/SysuiTestableContext.java b/packages/SystemUI/tests/src/com/android/systemui/SysuiTestableContext.java
index e811270..f792d7d 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/SysuiTestableContext.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/SysuiTestableContext.java
@@ -18,6 +18,7 @@
import android.testing.LeakCheck;
import android.testing.TestableContext;
import android.util.ArrayMap;
+import android.view.Display;
public class SysuiTestableContext extends TestableContext implements SysUiServiceProvider {
@@ -47,4 +48,15 @@
if (mComponents == null) mComponents = new ArrayMap<>();
mComponents.put(interfaceType, component);
}
+
+ @Override
+ public Context createDisplayContext(Display display) {
+ if (display == null) {
+ throw new IllegalArgumentException("display must not be null");
+ }
+
+ SysuiTestableContext context =
+ new SysuiTestableContext(getBaseContext().createDisplayContext(display));
+ return context;
+ }
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/tileimpl/QSTileImplTest.java b/packages/SystemUI/tests/src/com/android/systemui/qs/tileimpl/QSTileImplTest.java
index 6764634..e5464e0 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/qs/tileimpl/QSTileImplTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/qs/tileimpl/QSTileImplTest.java
@@ -19,8 +19,10 @@
import static com.android.internal.logging.nano.MetricsProto.MetricsEvent.ACTION_QS_SECONDARY_CLICK;
import static com.android.internal.logging.nano.MetricsProto.MetricsEvent.FIELD_QS_POSITION;
import static com.android.internal.logging.nano.MetricsProto.MetricsEvent.FIELD_QS_VALUE;
+import static com.android.internal.logging.nano.MetricsProto.MetricsEvent.FIELD_STATUS_BAR_STATE;
import static com.android.internal.logging.nano.MetricsProto.MetricsEvent.TYPE_ACTION;
+import static org.junit.Assert.assertEquals;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyInt;
import static org.mockito.ArgumentMatchers.eq;
@@ -37,7 +39,6 @@
import android.content.Intent;
import android.metrics.LogMaker;
import android.support.test.filters.SmallTest;
-import android.support.test.InstrumentationRegistry;
import android.testing.AndroidTestingRunner;
import android.testing.TestableLooper;
import android.testing.TestableLooper.RunWithLooper;
@@ -48,12 +49,17 @@
import com.android.systemui.plugins.qs.QSTile;
import com.android.systemui.qs.QSHost;
import com.android.systemui.qs.QSTileHost;
+import com.android.systemui.statusbar.StatusBarState;
+import com.android.systemui.statusbar.StatusBarStateController;
import org.junit.Before;
import org.junit.Ignore;
import org.junit.Test;
import org.junit.runner.RunWith;
+import org.mockito.ArgumentCaptor;
import org.mockito.ArgumentMatcher;
+import org.mockito.Captor;
+import org.mockito.MockitoAnnotations;
@RunWith(AndroidTestingRunner.class)
@RunWithLooper
@@ -65,13 +71,20 @@
private TileImpl mTile;
private QSTileHost mHost;
private MetricsLogger mMetricsLogger;
+ private StatusBarStateController mStatusBarStateController;
+
+ @Captor
+ private ArgumentCaptor<LogMaker> mLogCaptor;
@Before
public void setup() throws Exception {
+ MockitoAnnotations.initMocks(this);
String spec = "spec";
mTestableLooper = TestableLooper.get(this);
mDependency.injectTestDependency(Dependency.BG_LOOPER, mTestableLooper.getLooper());
mMetricsLogger = mDependency.injectMockDependency(MetricsLogger.class);
+ mStatusBarStateController =
+ mDependency.injectMockDependency(StatusBarStateController.class);
mHost = mock(QSTileHost.class);
when(mHost.indexOf(spec)).thenReturn(POSITION);
when(mHost.getContext()).thenReturn(mContext.getBaseContext());
@@ -88,19 +101,57 @@
}
@Test
+ public void testClick_Metrics_Status_Bar_Status() {
+ when(mStatusBarStateController.getState()).thenReturn(StatusBarState.SHADE);
+ mTile.click();
+ verify(mMetricsLogger).write(mLogCaptor.capture());
+ assertEquals(StatusBarState.SHADE, mLogCaptor.getValue()
+ .getTaggedData(FIELD_STATUS_BAR_STATE));
+ }
+
+ @Test
public void testSecondaryClick_Metrics() {
mTile.secondaryClick();
verify(mMetricsLogger).write(argThat(new TileLogMatcher(ACTION_QS_SECONDARY_CLICK)));
}
@Test
+ public void testSecondaryClick_Metrics_Status_Bar_Status() {
+ when(mStatusBarStateController.getState()).thenReturn(StatusBarState.KEYGUARD);
+ mTile.secondaryClick();
+ verify(mMetricsLogger).write(mLogCaptor.capture());
+ assertEquals(StatusBarState.KEYGUARD, mLogCaptor.getValue()
+ .getTaggedData(FIELD_STATUS_BAR_STATE));
+ }
+
+ @Test
public void testLongClick_Metrics() {
mTile.longClick();
verify(mMetricsLogger).write(argThat(new TileLogMatcher(ACTION_QS_LONG_PRESS)));
}
@Test
- public void testPopulate() {
+ public void testLongClick_Metrics_Status_Bar_Status() {
+ when(mStatusBarStateController.getState()).thenReturn(StatusBarState.SHADE_LOCKED);
+ mTile.click();
+ verify(mMetricsLogger).write(mLogCaptor.capture());
+ assertEquals(StatusBarState.SHADE_LOCKED, mLogCaptor.getValue()
+ .getTaggedData(FIELD_STATUS_BAR_STATE));
+ }
+
+ @Test
+ public void testPopulateWithLockedScreen() {
+ LogMaker maker = mock(LogMaker.class);
+ when(maker.setSubtype(anyInt())).thenReturn(maker);
+ when(maker.addTaggedData(anyInt(), any())).thenReturn(maker);
+ mTile.getState().value = true;
+ mTile.populate(maker);
+ verify(maker).addTaggedData(eq(FIELD_QS_VALUE), eq(1));
+ verify(maker).addTaggedData(eq(FIELD_QS_POSITION), eq(POSITION));
+ }
+
+ @Test
+ public void testPopulateWithUnlockedScreen() {
LogMaker maker = mock(LogMaker.class);
when(maker.setSubtype(anyInt())).thenReturn(maker);
when(maker.addTaggedData(anyInt(), any())).thenReturn(maker);
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NavigationBarButtonTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NavigationBarButtonTest.java
new file mode 100644
index 0000000..73f3b43
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NavigationBarButtonTest.java
@@ -0,0 +1,101 @@
+/*
+ * 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.statusbar.phone;
+
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertTrue;
+import static org.mockito.Mockito.mock;
+
+import android.graphics.PixelFormat;
+import android.hardware.display.DisplayManager;
+import android.hardware.display.VirtualDisplay;
+import android.media.ImageReader;
+import android.support.test.filters.SmallTest;
+import android.testing.AndroidTestingRunner;
+import android.testing.TestableLooper.RunWithLooper;
+import android.view.Display;
+import android.view.DisplayInfo;
+
+import com.android.systemui.SysuiTestCase;
+import com.android.systemui.SysuiTestableContext;
+import com.android.systemui.statusbar.CommandQueue;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+/** atest NavigationBarButtonTest */
+@RunWith(AndroidTestingRunner.class)
+@RunWithLooper
+@SmallTest
+public class NavigationBarButtonTest extends SysuiTestCase {
+
+ private ImageReader mReader;
+ private NavigationBarView mNavBar;
+ private VirtualDisplay mVirtualDisplay;
+
+ @Before
+ public void setup() {
+ final Display display = createVirtualDisplay();
+ final SysuiTestableContext context =
+ (SysuiTestableContext) mContext.createDisplayContext(display);
+ context.putComponent(CommandQueue.class, mock(CommandQueue.class));
+
+ mNavBar = new NavigationBarView(context, null);
+ }
+
+ private Display createVirtualDisplay() {
+ final String displayName = "NavVirtualDisplay";
+ final DisplayInfo displayInfo = new DisplayInfo();
+ mContext.getDisplay().getDisplayInfo(displayInfo);
+
+ final DisplayManager displayManager = mContext.getSystemService(DisplayManager.class);
+
+ mReader = ImageReader.newInstance(displayInfo.logicalWidth,
+ displayInfo.logicalHeight, PixelFormat.RGBA_8888, 2);
+
+ assertNotNull("ImageReader must not be null", mReader);
+
+ mVirtualDisplay = displayManager.createVirtualDisplay(displayName, displayInfo.logicalWidth,
+ displayInfo.logicalHeight, displayInfo.logicalDensityDpi, mReader.getSurface(),
+ 0 /*flags*/);
+
+ assertNotNull("virtual display must not be null", mVirtualDisplay);
+
+ return mVirtualDisplay.getDisplay();
+ }
+
+ @After
+ public void tearDown() {
+ releaseDisplay();
+ }
+
+ private void releaseDisplay() {
+ mVirtualDisplay.release();
+ mReader.close();
+ }
+
+ @Test
+ public void testRecentsButtonDisabledOnSecondaryDisplay() {
+ assertTrue("The recents button must be disabled",
+ mNavBar.isRecentsButtonDisabled());
+ }
+}
+
+
+
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/QuickStepControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/QuickStepControllerTest.java
index cdaa242..abb8c79 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/QuickStepControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/QuickStepControllerTest.java
@@ -61,6 +61,10 @@
@RunWithLooper
@SmallTest
public class QuickStepControllerTest extends SysuiTestCase {
+ private static final int NAVBAR_WIDTH = 1000;
+ private static final int NAVBAR_HEIGHT = 300;
+ private static final int EDGE_THRESHOLD = 100;
+
private QuickStepController mController;
private NavigationBarView mNavigationBarView;
private StatusBar mStatusBar;
@@ -73,6 +77,8 @@
MockitoAnnotations.initMocks(this);
final ButtonDispatcher backButton = mock(ButtonDispatcher.class);
mResources = mock(Resources.class);
+ doReturn(EDGE_THRESHOLD).when(mResources)
+ .getDimensionPixelSize(R.dimen.navigation_bar_edge_swipe_threshold);
mProxyService = mock(OverviewProxyService.class);
mProxy = mock(IOverviewProxy.Stub.class);
@@ -109,7 +115,8 @@
public void testNoGesturesWhenSwipeUpDisabled() throws Exception {
doReturn(false).when(mProxyService).shouldShowSwipeUpUI();
mController.setGestureActions(mockAction(true), null /* swipeDownAction */,
- null /* swipeLeftAction */, null /* swipeRightAction */);
+ null /* swipeLeftAction */, null /* swipeRightAction */, null /* leftEdgeSwipe */,
+ null /* rightEdgeSwipe */);
MotionEvent ev = event(MotionEvent.ACTION_DOWN, 1, 1);
assertFalse(mController.onInterceptTouchEvent(ev));
@@ -124,7 +131,8 @@
// Add enabled gesture action
NavigationGestureAction action = mockAction(true);
mController.setGestureActions(action, null /* swipeDownAction */,
- null /* swipeLeftAction */, null /* swipeRightAction */);
+ null /* swipeLeftAction */, null /* swipeRightAction */, null /* leftEdgeSwipe */,
+ null /* rightEdgeSwipe */);
assertFalse(mController.onInterceptTouchEvent(ev));
verify(mNavigationBarView, times(1)).requestUnbufferedDispatch(ev);
@@ -140,7 +148,8 @@
// Add enabled gesture action
mController.setGestureActions(mockAction(true), null /* swipeDownAction */,
- null /* swipeLeftAction */, null /* swipeRightAction */);
+ null /* swipeLeftAction */, null /* swipeRightAction */, null /* leftEdgeSwipe */,
+ null /* rightEdgeSwipe */);
// Set the gesture on deadzone
doReturn(null).when(mProxyService).getProxy();
@@ -165,7 +174,8 @@
@Test
public void testOnTouchIgnoredDownEventAfterOnIntercept() {
mController.setGestureActions(mockAction(true), null /* swipeDownAction */,
- null /* swipeLeftAction */, null /* swipeRightAction */);
+ null /* swipeLeftAction */, null /* swipeRightAction */, null /* leftEdgeSwipe */,
+ null /* rightEdgeSwipe */);
MotionEvent ev = event(MotionEvent.ACTION_DOWN, 1, 1);
assertFalse(touch(ev));
@@ -178,29 +188,45 @@
@Test
public void testGesturesCallCorrectAction() throws Exception {
+ doReturn(NAVBAR_WIDTH).when(mNavigationBarView).getWidth();
+ doReturn(NAVBAR_HEIGHT).when(mNavigationBarView).getHeight();
+
NavigationGestureAction swipeUp = mockAction(true);
NavigationGestureAction swipeDown = mockAction(true);
NavigationGestureAction swipeLeft = mockAction(true);
NavigationGestureAction swipeRight = mockAction(true);
- mController.setGestureActions(swipeUp, swipeDown, swipeLeft, swipeRight);
+ NavigationGestureAction swipeLeftFromEdge = mockAction(true);
+ NavigationGestureAction swipeRightFromEdge = mockAction(true);
+ mController.setGestureActions(swipeUp, swipeDown, swipeLeft, swipeRight, swipeLeftFromEdge,
+ swipeRightFromEdge);
// Swipe Up
assertGestureTriggersAction(swipeUp, 1, 100, 5, 1);
// Swipe Down
assertGestureTriggersAction(swipeDown, 1, 1, 5, 100);
// Swipe Left
- assertGestureTriggersAction(swipeLeft, 100, 1, 5, 1);
+ assertGestureTriggersAction(swipeLeft, NAVBAR_WIDTH / 2, 1, 5, 1);
// Swipe Right
- assertGestureTriggersAction(swipeRight, 1, 1, 100, 5);
+ assertGestureTriggersAction(swipeRight, NAVBAR_WIDTH / 2, 1, NAVBAR_WIDTH, 5);
+ // Swipe Left from Edge
+ assertGestureTriggersAction(swipeLeftFromEdge, NAVBAR_WIDTH, 1, 5, 1);
+ // Swipe Right from Edge
+ assertGestureTriggersAction(swipeRightFromEdge, 0, 1, NAVBAR_WIDTH, 5);
}
@Test
public void testGesturesCallCorrectActionLandscape() throws Exception {
+ doReturn(NAVBAR_HEIGHT).when(mNavigationBarView).getWidth();
+ doReturn(NAVBAR_WIDTH).when(mNavigationBarView).getHeight();
+
NavigationGestureAction swipeUp = mockAction(true);
NavigationGestureAction swipeDown = mockAction(true);
NavigationGestureAction swipeLeft = mockAction(true);
NavigationGestureAction swipeRight = mockAction(true);
- mController.setGestureActions(swipeUp, swipeDown, swipeLeft, swipeRight);
+ NavigationGestureAction swipeLeftFromEdge = mockAction(true);
+ NavigationGestureAction swipeRightFromEdge = mockAction(true);
+ mController.setGestureActions(swipeUp, swipeDown, swipeLeft, swipeRight, swipeLeftFromEdge,
+ swipeRightFromEdge);
// In landscape
mController.setBarState(false /* isRTL */, NAV_BAR_RIGHT);
@@ -208,34 +234,50 @@
// Swipe Up
assertGestureTriggersAction(swipeRight, 1, 100, 5, 1);
// Swipe Down
- assertGestureTriggersAction(swipeLeft, 1, 1, 5, 100);
+ assertGestureTriggersAction(swipeLeft, 1, NAVBAR_WIDTH / 2, 5, NAVBAR_WIDTH);
// Swipe Left
assertGestureTriggersAction(swipeUp, 100, 1, 5, 1);
// Swipe Right
assertGestureTriggersAction(swipeDown, 1, 1, 100, 5);
+ // Swipe Up from Edge
+ assertGestureTriggersAction(swipeRightFromEdge, 1, NAVBAR_WIDTH, 5, 0);
+ // Swipe Down from Edge
+ assertGestureTriggersAction(swipeLeftFromEdge, 0, 1, 0, NAVBAR_WIDTH);
}
@Test
public void testGesturesCallCorrectActionSeascape() throws Exception {
+ doReturn(NAVBAR_HEIGHT).when(mNavigationBarView).getWidth();
+ doReturn(NAVBAR_WIDTH).when(mNavigationBarView).getHeight();
+
mController.setBarState(false /* isRTL */, NAV_BAR_LEFT);
NavigationGestureAction swipeUp = mockAction(true);
NavigationGestureAction swipeDown = mockAction(true);
NavigationGestureAction swipeLeft = mockAction(true);
NavigationGestureAction swipeRight = mockAction(true);
- mController.setGestureActions(swipeUp, swipeDown, swipeLeft, swipeRight);
+ NavigationGestureAction swipeLeftFromEdge = mockAction(true);
+ NavigationGestureAction swipeRightFromEdge = mockAction(true);
+ mController.setGestureActions(swipeUp, swipeDown, swipeLeft, swipeRight, swipeLeftFromEdge,
+ swipeRightFromEdge);
// Swipe Up
- assertGestureTriggersAction(swipeLeft, 1, 100, 5, 1);
+ assertGestureTriggersAction(swipeLeft, 1, NAVBAR_WIDTH / 2, 5, 1);
// Swipe Down
- assertGestureTriggersAction(swipeRight, 1, 1, 5, 100);
+ assertGestureTriggersAction(swipeRight, 1, NAVBAR_WIDTH / 2, 5, NAVBAR_WIDTH);
// Swipe Left
assertGestureTriggersAction(swipeDown, 100, 1, 5, 1);
// Swipe Right
assertGestureTriggersAction(swipeUp, 1, 1, 100, 5);
+ // Swipe Up from Edge
+ assertGestureTriggersAction(swipeLeftFromEdge, 1, NAVBAR_WIDTH, 5, 0);
+ // Swipe Down from Edge
+ assertGestureTriggersAction(swipeRightFromEdge, 0, 1, 0, NAVBAR_WIDTH);
}
@Test
public void testGesturesCallCorrectActionRTL() throws Exception {
+ doReturn(NAVBAR_WIDTH).when(mNavigationBarView).getWidth();
+ doReturn(NAVBAR_HEIGHT).when(mNavigationBarView).getHeight();
mController.setBarState(true /* isRTL */, NAV_BAR_BOTTOM);
// The swipe gestures below are for LTR, so RTL in portrait will be swapped
@@ -243,20 +285,29 @@
NavigationGestureAction swipeDown = mockAction(true);
NavigationGestureAction swipeLeft = mockAction(true);
NavigationGestureAction swipeRight = mockAction(true);
- mController.setGestureActions(swipeUp, swipeDown, swipeLeft, swipeRight);
+ NavigationGestureAction swipeLeftFromEdge = mockAction(true);
+ NavigationGestureAction swipeRightFromEdge = mockAction(true);
+ mController.setGestureActions(swipeUp, swipeDown, swipeLeft, swipeRight, swipeLeftFromEdge,
+ swipeRightFromEdge);
// Swipe Up in RTL
assertGestureTriggersAction(swipeUp, 1, 100, 5, 1);
// Swipe Down in RTL
assertGestureTriggersAction(swipeDown, 1, 1, 5, 100);
// Swipe Left in RTL
- assertGestureTriggersAction(swipeRight, 100, 1, 5, 1);
+ assertGestureTriggersAction(swipeRight, NAVBAR_WIDTH / 2, 1, 5, 1);
// Swipe Right in RTL
- assertGestureTriggersAction(swipeLeft, 1, 1, 100, 5);
+ assertGestureTriggersAction(swipeLeft, NAVBAR_WIDTH / 2, 1, NAVBAR_WIDTH, 0);
+ // Swipe Left from Edge
+ assertGestureTriggersAction(swipeRightFromEdge, NAVBAR_WIDTH, 1, 5, 1);
+ // Swipe Right from Edge
+ assertGestureTriggersAction(swipeLeftFromEdge, 0, 1, NAVBAR_WIDTH, 5);
}
@Test
public void testGesturesCallCorrectActionLandscapeRTL() throws Exception {
+ doReturn(NAVBAR_HEIGHT).when(mNavigationBarView).getWidth();
+ doReturn(NAVBAR_WIDTH).when(mNavigationBarView).getHeight();
mController.setBarState(true /* isRTL */, NAV_BAR_RIGHT);
// The swipe gestures below are for LTR, so RTL in landscape will be swapped
@@ -264,20 +315,29 @@
NavigationGestureAction swipeDown = mockAction(true);
NavigationGestureAction swipeLeft = mockAction(true);
NavigationGestureAction swipeRight = mockAction(true);
- mController.setGestureActions(swipeUp, swipeDown, swipeLeft, swipeRight);
+ NavigationGestureAction swipeLeftFromEdge = mockAction(true);
+ NavigationGestureAction swipeRightFromEdge = mockAction(true);
+ mController.setGestureActions(swipeUp, swipeDown, swipeLeft, swipeRight, swipeLeftFromEdge,
+ swipeRightFromEdge);
// Swipe Up
- assertGestureTriggersAction(swipeLeft, 1, 100, 5, 1);
+ assertGestureTriggersAction(swipeLeft, 1, NAVBAR_WIDTH / 2, 5, 1);
// Swipe Down
- assertGestureTriggersAction(swipeRight, 1, 1, 5, 100);
+ assertGestureTriggersAction(swipeRight, 1, NAVBAR_WIDTH / 2, 5, NAVBAR_WIDTH);
// Swipe Left
assertGestureTriggersAction(swipeUp, 100, 1, 5, 1);
// Swipe Right
assertGestureTriggersAction(swipeDown, 1, 1, 100, 5);
+ // Swipe Up from Edge
+ assertGestureTriggersAction(swipeLeftFromEdge, 1, NAVBAR_WIDTH, 5, 0);
+ // Swipe Down from Edge
+ assertGestureTriggersAction(swipeRightFromEdge, 0, 1, 0, NAVBAR_WIDTH);
}
@Test
public void testGesturesCallCorrectActionSeascapeRTL() throws Exception {
+ doReturn(NAVBAR_HEIGHT).when(mNavigationBarView).getWidth();
+ doReturn(NAVBAR_WIDTH).when(mNavigationBarView).getHeight();
mController.setBarState(true /* isRTL */, NAV_BAR_LEFT);
// The swipe gestures below are for LTR, so RTL in seascape will be swapped
@@ -285,16 +345,23 @@
NavigationGestureAction swipeDown = mockAction(true);
NavigationGestureAction swipeLeft = mockAction(true);
NavigationGestureAction swipeRight = mockAction(true);
- mController.setGestureActions(swipeUp, swipeDown, swipeLeft, swipeRight);
+ NavigationGestureAction swipeLeftFromEdge = mockAction(true);
+ NavigationGestureAction swipeRightFromEdge = mockAction(true);
+ mController.setGestureActions(swipeUp, swipeDown, swipeLeft, swipeRight, swipeLeftFromEdge,
+ swipeRightFromEdge);
// Swipe Up
- assertGestureTriggersAction(swipeRight, 1, 100, 5, 1);
+ assertGestureTriggersAction(swipeRight, 1, NAVBAR_WIDTH / 2, 5, 1);
// Swipe Down
- assertGestureTriggersAction(swipeLeft, 1, 1, 5, 100);
+ assertGestureTriggersAction(swipeLeft, 1, NAVBAR_WIDTH / 2, 5, NAVBAR_WIDTH);
// Swipe Left
assertGestureTriggersAction(swipeDown, 100, 1, 5, 1);
// Swipe Right
assertGestureTriggersAction(swipeUp, 1, 1, 100, 5);
+ // Swipe Up from Edge
+ assertGestureTriggersAction(swipeRightFromEdge, 1, NAVBAR_WIDTH, 5, 0);
+ // Swipe Down from Edge
+ assertGestureTriggersAction(swipeLeftFromEdge, 0, 1, 0, NAVBAR_WIDTH);
}
@Test
@@ -305,7 +372,8 @@
// Add enabled gesture action
NavigationGestureAction action = mockAction(true);
mController.setGestureActions(action, null /* swipeDownAction */,
- null /* swipeLeftAction */, null /* swipeRightAction */);
+ null /* swipeLeftAction */, null /* swipeRightAction */, null /* leftEdgeSwipe */,
+ null /* rightEdgeSwipe */);
// Touch down to begin swipe
MotionEvent downEvent = event(MotionEvent.ACTION_DOWN, 1, 100);
@@ -326,7 +394,8 @@
NavigationGestureAction action = mockAction(true);
doReturn(false).when(action).canRunWhenNotificationsShowing();
mController.setGestureActions(action, null /* swipeDownAction */,
- null /* swipeLeftAction */, null /* swipeRightAction */);
+ null /* swipeLeftAction */, null /* swipeRightAction */, null /* leftEdgeSwipe */,
+ null /* rightEdgeSwipe */);
// Show the notifications
doReturn(false).when(mNavigationBarView).isNotificationsFullyCollapsed();
@@ -351,7 +420,8 @@
public void testActionCannotPerform() throws Exception {
NavigationGestureAction action = mockAction(true);
mController.setGestureActions(action, null /* swipeDownAction */,
- null /* swipeLeftAction */, null /* swipeRightAction */);
+ null /* swipeLeftAction */, null /* swipeRightAction */, null /* leftEdgeSwipe */,
+ null /* rightEdgeSwipe */);
// Cannot perform action
doReturn(false).when(action).canPerformAction();
@@ -374,13 +444,17 @@
@Test
public void testQuickScrub() throws Exception {
+ doReturn(NAVBAR_WIDTH).when(mNavigationBarView).getWidth();
+ doReturn(NAVBAR_HEIGHT).when(mNavigationBarView).getHeight();
QuickScrubAction action = spy(new QuickScrubAction(mNavigationBarView, mProxyService));
mController.setGestureActions(null /* swipeUpAction */, null /* swipeDownAction */,
- null /* swipeLeftAction */, action);
+ null /* swipeLeftAction */, action, null /* leftEdgeSwipe */,
+ null /* rightEdgeSwipe */);
+ int x = NAVBAR_WIDTH / 2;
int y = 20;
// Set the layout and other padding to make sure the scrub fraction is calculated correctly
- action.onLayout(true, 0, 0, 400, 100);
+ action.onLayout(true, 0, 0, NAVBAR_WIDTH, NAVBAR_HEIGHT);
doReturn(0).when(mNavigationBarView).getPaddingLeft();
doReturn(0).when(mNavigationBarView).getPaddingRight();
doReturn(0).when(mNavigationBarView).getPaddingStart();
@@ -393,14 +467,14 @@
doReturn(true).when(mNavigationBarView).isQuickScrubEnabled();
// Touch down
- MotionEvent downEvent = event(MotionEvent.ACTION_DOWN, 0, y);
+ MotionEvent downEvent = event(MotionEvent.ACTION_DOWN, x, y);
assertFalse(touch(downEvent));
assertNull(mController.getCurrentAction());
verify(mProxy, times(1)).onPreMotionEvent(mNavigationBarView.getDownHitTarget());
verify(mProxy, times(1)).onMotionEvent(downEvent);
// Move to start trigger action from gesture
- MotionEvent moveEvent1 = event(MotionEvent.ACTION_MOVE, 100, y);
+ MotionEvent moveEvent1 = event(MotionEvent.ACTION_MOVE, x + 100, y);
assertTrue(touch(moveEvent1));
assertEquals(action, mController.getCurrentAction());
verify(action, times(1)).onGestureStart(moveEvent1);
@@ -410,11 +484,13 @@
verify(mProxy, never()).onMotionEvent(moveEvent1);
// Move again for scrub
- MotionEvent moveEvent2 = event(MotionEvent.ACTION_MOVE, 200, y);
+ float fraction = 3f / 4;
+ x = (int) (NAVBAR_WIDTH * fraction);
+ MotionEvent moveEvent2 = event(MotionEvent.ACTION_MOVE, x, y);
assertTrue(touch(moveEvent2));
assertEquals(action, mController.getCurrentAction());
- verify(action, times(1)).onGestureMove(200, y);
- verify(mProxy, times(1)).onQuickScrubProgress(1f / 2);
+ verify(action, times(1)).onGestureMove(x, y);
+ verify(mProxy, times(1)).onQuickScrubProgress(fraction);
verify(mProxy, never()).onMotionEvent(moveEvent2);
// Action up
@@ -430,7 +506,8 @@
public void testQuickStep() throws Exception {
QuickStepAction action = new QuickStepAction(mNavigationBarView, mProxyService);
mController.setGestureActions(action, null /* swipeDownAction */,
- null /* swipeLeftAction */, null /* swipeRightAction */);
+ null /* swipeLeftAction */, null /* swipeRightAction */, null /* leftEdgeSwipe */,
+ null /* rightEdgeSwipe */);
// Notifications are up, should prevent quickstep
doReturn(false).when(mNavigationBarView).isNotificationsFullyCollapsed();
@@ -466,7 +543,8 @@
public void testLongPressPreventDetection() throws Exception {
NavigationGestureAction action = mockAction(true);
mController.setGestureActions(action, null /* swipeDownAction */,
- null /* swipeLeftAction */, null /* swipeRightAction */);
+ null /* swipeLeftAction */, null /* swipeRightAction */, null /* leftEdgeSwipe */,
+ null /* rightEdgeSwipe */);
// Start the drag up
assertFalse(touch(MotionEvent.ACTION_DOWN, 100, 1));
@@ -488,23 +566,21 @@
@Test
public void testHitTargetDragged() throws Exception {
- final int navbarWidth = 1000;
- final int navbarHeight = 1000;
ButtonDispatcher button = mock(ButtonDispatcher.class);
- FakeLocationView buttonView = spy(new FakeLocationView(mContext, navbarWidth / 2,
- navbarHeight / 2));
+ FakeLocationView buttonView = spy(new FakeLocationView(mContext, NAVBAR_WIDTH / 2,
+ NAVBAR_HEIGHT / 2));
doReturn(buttonView).when(button).getCurrentView();
NavigationGestureAction action = mockAction(true);
- mController.setGestureActions(action, action, action, action);
+ mController.setGestureActions(action, action, action, action, action, action);
// Setup getting the hit target
doReturn(HIT_TARGET_HOME).when(action).requiresTouchDownHitTarget();
- doReturn(true).when(action).requiresDragWithHitTarget();
+ doReturn(true).when(action).allowHitTargetToMoveOverDrag();
doReturn(HIT_TARGET_HOME).when(mNavigationBarView).getDownHitTarget();
doReturn(button).when(mNavigationBarView).getHomeButton();
- doReturn(navbarWidth).when(mNavigationBarView).getWidth();
- doReturn(navbarHeight).when(mNavigationBarView).getHeight();
+ doReturn(NAVBAR_WIDTH).when(mNavigationBarView).getWidth();
+ doReturn(NAVBAR_HEIGHT).when(mNavigationBarView).getHeight();
// Portrait
assertGestureDragsHitTargetAllDirections(buttonView, false /* isRTL */, NAV_BAR_BOTTOM);
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarNotificationPresenterTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarNotificationPresenterTest.java
index 27123e4..02f8949 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarNotificationPresenterTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarNotificationPresenterTest.java
@@ -70,7 +70,7 @@
mock(NotificationPanelView.class), mock(HeadsUpManagerPhone.class),
statusBarWindowView, mock(NotificationListContainerViewGroup.class),
mock(DozeScrimController.class), mock(ScrimController.class),
- mock(ActivityLaunchAnimator.class));
+ mock(ActivityLaunchAnimator.class), mock(StatusBarKeyguardViewManager.class));
}
@Test
diff --git a/proto/src/metrics_constants/metrics_constants.proto b/proto/src/metrics_constants/metrics_constants.proto
index 89220d5..f2ae161 100644
--- a/proto/src/metrics_constants/metrics_constants.proto
+++ b/proto/src/metrics_constants/metrics_constants.proto
@@ -6609,6 +6609,24 @@
// OS: Q
DIALOG_DISABLE_DEVELOPMENT_OPTIONS = 1591;
+ // Tag for an ACTION: QS -> Tile click / Secondary click / long press
+ // indicating the StatusBarState when menu was pulled down
+ // CATEGORY: QUICK_SETTINGS
+ // OS: Q
+ FIELD_STATUS_BAR_STATE = 1592;
+
+ // Tag for an ACTION: QS -> Tile click / Secondary click / long press
+ // indicating whether current state is full QS
+ // CATEGORY: QUICK_SETTINGS
+ // OS: Q
+ FIELD_IS_FULL_QS = 1593;
+
+ // ACTION: Display folding state was changed
+ // CATEGORY: OTHER
+ // SUBTYPE: 1 if display is folded, 0 if not.
+ // OS: Q
+ ACTION_DISPLAY_FOLD = 1594;
+
// ---- End Q Constants, all Q constants go above this line ----
// Add new aosp constants above this line.
diff --git a/proto/src/wifi.proto b/proto/src/wifi.proto
index 1fda074..e9ce737 100644
--- a/proto/src/wifi.proto
+++ b/proto/src/wifi.proto
@@ -1344,6 +1344,27 @@
// Amount of time wifi is in tx (ms)
optional int64 tx_time_ms = 5;
+
+ // Amount of time kernel is active because of wifi data (ms)
+ optional int64 wifi_kernel_active_time_ms = 6;
+
+ // Number of packets sent (tx)
+ optional int64 num_packets_tx = 7;
+
+ // Number of bytes sent (tx)
+ optional int64 num_bytes_tx = 8;
+
+ // Number of packets received (rx)
+ optional int64 num_packets_rx = 9;
+
+ // Number of bytes sent (rx)
+ optional int64 num_bytes_rx = 10;
+
+ // Amount of time wifi is in sleep (ms)
+ optional int64 sleep_time_ms = 11;
+
+ // Amount of time wifi is scanning (ms)
+ optional int64 scan_time_ms = 12;
}
// Metrics for Wifi Wake
diff --git a/services/autofill/java/com/android/server/autofill/Session.java b/services/autofill/java/com/android/server/autofill/Session.java
index d76a5df..aef16b1 100644
--- a/services/autofill/java/com/android/server/autofill/Session.java
+++ b/services/autofill/java/com/android/server/autofill/Session.java
@@ -1238,7 +1238,15 @@
return;
}
- final UserData userData = mService.getUserData();
+ final UserData packageUserData = lastResponse.getUserData();
+
+ final UserData userData;
+ if (packageUserData != null) {
+ // Replace default userData
+ userData = packageUserData;
+ } else {
+ userData = mService.getUserData();
+ }
for (int i = 0; i < mViewStates.size(); i++) {
final ViewState viewState = mViewStates.valueAt(i);
diff --git a/services/backup/java/com/android/server/backup/BackupManagerService.java b/services/backup/java/com/android/server/backup/BackupManagerService.java
index 0b06f28..3acdc8e3 100644
--- a/services/backup/java/com/android/server/backup/BackupManagerService.java
+++ b/services/backup/java/com/android/server/backup/BackupManagerService.java
@@ -27,7 +27,6 @@
import android.app.job.JobScheduler;
import android.app.job.JobService;
import android.content.ComponentName;
-import android.content.ContentResolver;
import android.content.Context;
import android.content.Intent;
import android.content.pm.PackageManager;
@@ -38,8 +37,6 @@
import android.os.RemoteException;
import android.os.Trace;
import android.os.UserHandle;
-import android.provider.Settings;
-import android.text.TextUtils;
import android.util.Slog;
import com.android.internal.annotations.VisibleForTesting;
@@ -82,11 +79,11 @@
return sInstance;
}
- /** Helper to create the {@link BackupManagerService} instance. */
- public static BackupManagerService create(
- Context context,
- Trampoline parent,
- HandlerThread backupThread) {
+ private UserBackupManagerService mUserBackupManagerService;
+
+ /** Instantiate a new instance of {@link BackupManagerService}. */
+ public BackupManagerService(
+ Context context, Trampoline trampoline, HandlerThread backupThread) {
// Set up our transport options and initialize the default transport
SystemConfig systemConfig = SystemConfig.getInstance();
Set<ComponentName> transportWhitelist = systemConfig.getBackupTransportWhitelist();
@@ -94,50 +91,9 @@
transportWhitelist = Collections.emptySet();
}
- String transport =
- Settings.Secure.getString(
- context.getContentResolver(), Settings.Secure.BACKUP_TRANSPORT);
- if (TextUtils.isEmpty(transport)) {
- transport = null;
- }
- if (DEBUG) {
- Slog.v(TAG, "Starting with transport " + transport);
- }
- TransportManager transportManager =
- new TransportManager(
- context,
- transportWhitelist,
- transport);
-
- // If encrypted file systems is enabled or disabled, this call will return the
- // correct directory.
- File baseStateDir = new File(Environment.getDataDirectory(), "backup");
-
- // This dir on /cache is managed directly in init.rc
- File dataDir = new File(Environment.getDownloadCacheDirectory(), "backup_stage");
-
- return new BackupManagerService(
- context,
- parent,
- backupThread,
- baseStateDir,
- dataDir,
- transportManager);
- }
-
- private UserBackupManagerService mUserBackupManagerService;
-
- /** Instantiate a new instance of {@link BackupManagerService}. */
- public BackupManagerService(
- Context context,
- Trampoline trampoline,
- HandlerThread backupThread,
- File baseStateDir,
- File dataDir,
- TransportManager transportManager) {
mUserBackupManagerService =
- new UserBackupManagerService(
- context, trampoline, backupThread, baseStateDir, dataDir, transportManager);
+ UserBackupManagerService.createAndInitializeService(
+ context, trampoline, backupThread, transportWhitelist);
}
// TODO(b/118520567): Remove when tests are modified to use per-user instance.
@@ -151,30 +107,6 @@
* a background thread to keep the unlock time down.
*/
public void unlockSystemUser() {
- // Migrate legacy setting
- Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "backup migrate");
- if (!backupSettingMigrated(UserHandle.USER_SYSTEM)) {
- if (DEBUG) {
- Slog.i(TAG, "Backup enable apparently not migrated");
- }
- ContentResolver resolver = sInstance.getContext().getContentResolver();
- int enableState = Settings.Secure.getIntForUser(resolver,
- Settings.Secure.BACKUP_ENABLED, -1, UserHandle.USER_SYSTEM);
- if (enableState >= 0) {
- if (DEBUG) {
- Slog.i(TAG, "Migrating enable state " + (enableState != 0));
- }
- writeBackupEnableState(enableState != 0, UserHandle.USER_SYSTEM);
- Settings.Secure.putStringForUser(resolver,
- Settings.Secure.BACKUP_ENABLED, null, UserHandle.USER_SYSTEM);
- } else {
- if (DEBUG) {
- Slog.i(TAG, "Backup not yet configured; retaining null enable state");
- }
- }
- }
- Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
-
Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "backup enable");
try {
sInstance.setBackupEnabled(readBackupEnableState(UserHandle.USER_SYSTEM));
@@ -184,6 +116,15 @@
Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
}
+ /**
+ * Starts the backup service for user {@code userId} by creating a new instance of {@link
+ * UserBackupManagerService} and registering it with this service.
+ */
+ // TODO(b/120212806): Add UserBackupManagerService initialization logic.
+ void startServiceForUser(int userId) {
+ // Intentionally empty.
+ }
+
/*
* The following methods are implementations of IBackupManager methods called from Trampoline.
* They delegate to the appropriate per-user instance of UserBackupManagerService to perform the
@@ -563,12 +504,6 @@
mUserBackupManagerService.dump(fd, pw, args);
}
- private static boolean backupSettingMigrated(int userId) {
- File base = new File(Environment.getDataDirectory(), "backup");
- File enableFile = new File(base, BACKUP_ENABLE_FILE);
- return enableFile.exists();
- }
-
private static boolean readBackupEnableState(int userId) {
File base = new File(Environment.getDataDirectory(), "backup");
File enableFile = new File(base, BACKUP_ENABLE_FILE);
@@ -598,14 +533,8 @@
stage.renameTo(enableFile);
// will be synced immediately by the try-with-resources call to close()
} catch (IOException | RuntimeException e) {
- // Whoops; looks like we're doomed. Roll everything out, disabled,
- // including the legacy state.
Slog.e(TAG, "Unable to record backup enable state; reverting to disabled: "
+ e.getMessage());
-
- ContentResolver resolver = sInstance.getContext().getContentResolver();
- Settings.Secure.putStringForUser(resolver,
- Settings.Secure.BACKUP_ENABLED, null, userId);
enableFile.delete();
stage.delete();
}
@@ -626,7 +555,9 @@
@Override
public void onUnlockUser(int userId) {
if (userId == UserHandle.USER_SYSTEM) {
- sInstance.unlockSystemUser();
+ sInstance.initializeServiceAndUnlockSystemUser();
+ } else {
+ sInstance.startServiceForUser(userId);
}
}
}
diff --git a/services/backup/java/com/android/server/backup/Trampoline.java b/services/backup/java/com/android/server/backup/Trampoline.java
index 59629aa..108f50d 100644
--- a/services/backup/java/com/android/server/backup/Trampoline.java
+++ b/services/backup/java/com/android/server/backup/Trampoline.java
@@ -41,6 +41,7 @@
import android.os.SystemProperties;
import android.os.Trace;
import android.os.UserHandle;
+import android.provider.Settings;
import android.util.Slog;
import com.android.internal.annotations.GuardedBy;
@@ -81,6 +82,12 @@
// Product-level suppression of backup/restore.
private static final String BACKUP_DISABLE_PROPERTY = "ro.backup.disable";
+ private static final String BACKUP_THREAD = "backup";
+
+ /** Values for setting {@link Settings.Global#BACKUP_MULTI_USER_ENABLED} */
+ private static final int MULTI_USER_DISABLED = 0;
+ private static final int MULTI_USER_ENABLED = 1;
+
private final Context mContext;
@GuardedBy("mStateLock")
@@ -91,18 +98,31 @@
private volatile BackupManagerService mService;
private HandlerThread mHandlerThread;
+ private Handler mHandler;
public Trampoline(Context context) {
mContext = context;
mGlobalDisable = isBackupDisabled();
mSuppressFile = getSuppressFile();
mSuppressFile.getParentFile().mkdirs();
+
+ mHandlerThread = new HandlerThread(BACKUP_THREAD, Process.THREAD_PRIORITY_BACKGROUND);
+ mHandlerThread.start();
+ mHandler = new Handler(mHandlerThread.getLooper());
}
protected boolean isBackupDisabled() {
return SystemProperties.getBoolean(BACKUP_DISABLE_PROPERTY, false);
}
+ protected boolean isMultiUserEnabled() {
+ return Settings.Global.getInt(
+ mContext.getContentResolver(),
+ Settings.Global.BACKUP_MULTI_USER_ENABLED,
+ MULTI_USER_DISABLED)
+ == MULTI_USER_ENABLED;
+ }
+
protected int binderGetCallingUid() {
return Binder.getCallingUid();
}
@@ -117,7 +137,7 @@
}
protected BackupManagerService createBackupManagerService() {
- return BackupManagerService.create(mContext, this, mHandlerThread);
+ return new BackupManagerService(mContext, this, mHandlerThread);
}
/**
@@ -147,15 +167,9 @@
/**
* Called from {@link BackupManagerService.Lifecycle} when the system user is unlocked. Attempts
* to initialize {@link BackupManagerService} and set backup state for the system user.
- *
- * @see BackupManagerService#unlockSystemUser()
*/
- void unlockSystemUser() {
- mHandlerThread = new HandlerThread("backup", Process.THREAD_PRIORITY_BACKGROUND);
- mHandlerThread.start();
-
- Handler h = new Handler(mHandlerThread.getLooper());
- h.post(
+ void initializeServiceAndUnlockSystemUser() {
+ mHandler.post(
() -> {
Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "backup init");
initializeService(UserHandle.USER_SYSTEM);
@@ -170,6 +184,29 @@
}
/**
+ * Called from {@link BackupManagerService.Lifecycle} when a non-system user {@code userId} is
+ * unlocked. Starts the backup service for this user if the service supports multi-user.
+ * Offloads work onto the handler thread {@link #mHandlerThread} to keep unlock time low.
+ */
+ // TODO(b/120212806): Consolidate service start for system and non-system users when system
+ // user-only logic is removed.
+ void startServiceForUser(int userId) {
+ if (!isMultiUserEnabled()) {
+ Slog.i(TAG, "Multi-user disabled, cannot start service for user: " + userId);
+ return;
+ }
+
+ mHandler.post(
+ () -> {
+ BackupManagerService service = mService;
+ if (service != null) {
+ Slog.i(TAG, "Starting service for user: " + userId);
+ service.startServiceForUser(userId);
+ }
+ });
+ }
+
+ /**
* Only privileged callers should be changing the backup state. This method only acts on {@link
* UserHandle#USER_SYSTEM} and is a no-op if passed non-system users. Deactivating backup in the
* system user also deactivates backup in all users.
diff --git a/services/backup/java/com/android/server/backup/UserBackupManagerService.java b/services/backup/java/com/android/server/backup/UserBackupManagerService.java
index fe16afe..5220a59 100644
--- a/services/backup/java/com/android/server/backup/UserBackupManagerService.java
+++ b/services/backup/java/com/android/server/backup/UserBackupManagerService.java
@@ -18,6 +18,7 @@
import static android.content.pm.ApplicationInfo.PRIVATE_FLAG_BACKUP_IN_FOREGROUND;
+import static com.android.internal.util.Preconditions.checkNotNull;
import static com.android.server.backup.BackupManagerService.DEBUG;
import static com.android.server.backup.BackupManagerService.DEBUG_SCHEDULING;
import static com.android.server.backup.BackupManagerService.MORE_DEBUG;
@@ -68,6 +69,7 @@
import android.net.Uri;
import android.os.Binder;
import android.os.Bundle;
+import android.os.Environment;
import android.os.Handler;
import android.os.HandlerThread;
import android.os.IBinder;
@@ -86,6 +88,7 @@
import android.os.storage.IStorageManager;
import android.os.storage.StorageManager;
import android.provider.Settings;
+import android.text.TextUtils;
import android.util.ArraySet;
import android.util.AtomicFile;
import android.util.EventLog;
@@ -167,6 +170,10 @@
// Persistently track the need to do a full init.
private static final String INIT_SENTINEL_FILE_NAME = "_need_init_";
+ // Name of the directories the service stores bookkeeping data under.
+ private static final String BACKUP_PERSISTENT_DIR = "backup";
+ private static final String BACKUP_STAGING_DIR = "backup_stage";
+
// System-private key used for backing up an app's widget state. Must
// begin with U+FFxx by convention (we reserve all keys starting
// with U+FF00 or higher for system use).
@@ -360,15 +367,71 @@
private long mAncestralToken = 0;
private long mCurrentToken = 0;
+ /**
+ * Creates an instance of {@link UserBackupManagerService} and initializes state for it. This
+ * includes setting up the directories where we keep our bookkeeping and transport management.
+ *
+ * @see #createAndInitializeService(Context, Trampoline, HandlerThread, File, File,
+ * TransportManager)
+ */
+ static UserBackupManagerService createAndInitializeService(
+ Context context,
+ Trampoline trampoline,
+ HandlerThread backupThread,
+ Set<ComponentName> transportWhitelist) {
+ String currentTransport =
+ Settings.Secure.getString(
+ context.getContentResolver(), Settings.Secure.BACKUP_TRANSPORT);
+ if (TextUtils.isEmpty(currentTransport)) {
+ currentTransport = null;
+ }
+
+ if (DEBUG) {
+ Slog.v(TAG, "Starting with transport " + currentTransport);
+ }
+ TransportManager transportManager =
+ new TransportManager(context, transportWhitelist, currentTransport);
+
+ File baseStateDir = new File(Environment.getDataDirectory(), BACKUP_PERSISTENT_DIR);
+
+ // This dir on /cache is managed directly in init.rc
+ File dataDir = new File(Environment.getDownloadCacheDirectory(), BACKUP_STAGING_DIR);
+
+ return createAndInitializeService(
+ context, trampoline, backupThread, baseStateDir, dataDir, transportManager);
+ }
+
+ /**
+ * Creates an instance of {@link UserBackupManagerService}.
+ *
+ * @param context The system server context.
+ * @param trampoline A reference to the proxy to {@link BackupManagerService}.
+ * @param backupThread The thread running backup/restore operations for the user.
+ * @param baseStateDir The directory we store the user's persistent bookkeeping data.
+ * @param dataDir The directory we store the user's temporary staging data.
+ * @param transportManager The {@link TransportManager} responsible for handling the user's
+ * transports.
+ */
@VisibleForTesting
- public UserBackupManagerService(
+ public static UserBackupManagerService createAndInitializeService(
+ Context context,
+ Trampoline trampoline,
+ HandlerThread backupThread,
+ File baseStateDir,
+ File dataDir,
+ TransportManager transportManager) {
+ return new UserBackupManagerService(
+ context, trampoline, backupThread, baseStateDir, dataDir, transportManager);
+ }
+
+ private UserBackupManagerService(
Context context,
Trampoline parent,
HandlerThread backupThread,
File baseStateDir,
File dataDir,
TransportManager transportManager) {
- mContext = context;
+ mContext = checkNotNull(context, "context cannot be null");
mPackageManager = context.getPackageManager();
mPackageManagerBinder = AppGlobals.getPackageManager();
mActivityManager = ActivityManager.getService();
@@ -377,6 +440,7 @@
mPowerManager = (PowerManager) context.getSystemService(Context.POWER_SERVICE);
mStorageManager = IStorageManager.Stub.asInterface(ServiceManager.getService("mount"));
+ checkNotNull(parent, "trampoline cannot be null");
mBackupManagerBinder = Trampoline.asInterface(parent.asBinder());
mAgentTimeoutParameters = new
@@ -384,6 +448,7 @@
mAgentTimeoutParameters.start();
// spin up the backup/restore handler thread
+ checkNotNull(backupThread, "backupThread cannot be null");
mBackupHandler = new BackupHandler(this, backupThread.getLooper());
// Set up our bookkeeping
@@ -398,13 +463,13 @@
Settings.Global.getUriFor(Settings.Global.DEVICE_PROVISIONED),
false, mProvisionedObserver);
- mBaseStateDir = baseStateDir;
+ mBaseStateDir = checkNotNull(baseStateDir, "baseStateDir cannot be null");
mBaseStateDir.mkdirs();
if (!SELinux.restorecon(mBaseStateDir)) {
Slog.e(TAG, "SELinux restorecon failed on " + mBaseStateDir);
}
- mDataDir = dataDir;
+ mDataDir = checkNotNull(dataDir, "dataDir cannot be null");
mBackupPasswordManager = new BackupPasswordManager(mContext, mBaseStateDir, mRng);
@@ -451,7 +516,7 @@
addPackageParticipantsLocked(null);
}
- mTransportManager = transportManager;
+ mTransportManager = checkNotNull(transportManager, "transportManager cannot be null");
mTransportManager.setOnTransportRegisteredListener(this::onTransportRegistered);
mRegisterTransportsRequestedTime = SystemClock.elapsedRealtime();
mBackupHandler.postDelayed(
@@ -465,7 +530,6 @@
mWakelock = mPowerManager.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "*backup*");
}
-
public BackupManagerConstants getConstants() {
return mConstants;
}
diff --git a/services/core/Android.bp b/services/core/Android.bp
index 70b8339..cccacf4 100644
--- a/services/core/Android.bp
+++ b/services/core/Android.bp
@@ -21,7 +21,6 @@
":mediaupdateservice_aidl",
"java/com/android/server/EventLogTags.logtags",
"java/com/android/server/am/EventLogTags.logtags",
- ":netd_aidl",
":netd_metrics_aidl",
],
diff --git a/services/core/java/com/android/server/LocationManagerService.java b/services/core/java/com/android/server/LocationManagerService.java
index cc7bf33..8b992eb 100644
--- a/services/core/java/com/android/server/LocationManagerService.java
+++ b/services/core/java/com/android/server/LocationManagerService.java
@@ -17,8 +17,11 @@
package com.android.server;
import static android.content.pm.PackageManager.PERMISSION_GRANTED;
+import static android.location.LocationProvider.AVAILABLE;
import static android.provider.Settings.Global.LOCATION_DISABLE_STATUS_CALLBACKS;
+import static com.android.internal.util.Preconditions.checkState;
+
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.app.ActivityManager;
@@ -47,14 +50,12 @@
import android.location.IGnssMeasurementsListener;
import android.location.IGnssNavigationMessageListener;
import android.location.IGnssStatusListener;
-import android.location.IGnssStatusProvider;
import android.location.IGpsGeofenceHardware;
import android.location.ILocationListener;
import android.location.ILocationManager;
import android.location.INetInitiatedListener;
import android.location.Location;
import android.location.LocationManager;
-import android.location.LocationProvider;
import android.location.LocationRequest;
import android.os.Binder;
import android.os.Bundle;
@@ -84,6 +85,7 @@
import com.android.internal.os.BackgroundThread;
import com.android.internal.util.ArrayUtils;
import com.android.internal.util.DumpUtils;
+import com.android.server.location.AbstractLocationProvider;
import com.android.server.location.ActivityRecognitionProxy;
import com.android.server.location.GeocoderProxy;
import com.android.server.location.GeofenceManager;
@@ -92,9 +94,9 @@
import com.android.server.location.GnssLocationProvider;
import com.android.server.location.GnssMeasurementsProvider;
import com.android.server.location.GnssNavigationMessageProvider;
+import com.android.server.location.GnssStatusListenerHelper;
import com.android.server.location.LocationBlacklist;
import com.android.server.location.LocationFudger;
-import com.android.server.location.LocationProviderInterface;
import com.android.server.location.LocationProviderProxy;
import com.android.server.location.LocationRequestStatistics;
import com.android.server.location.LocationRequestStatistics.PackageProviderKey;
@@ -131,8 +133,6 @@
// Location resolution level: fine location data
private static final int RESOLUTION_LEVEL_FINE = 2;
- private static final String ACCESS_MOCK_LOCATION =
- android.Manifest.permission.ACCESS_MOCK_LOCATION;
private static final String ACCESS_LOCATION_EXTRA_COMMANDS =
android.Manifest.permission.ACCESS_LOCATION_EXTRA_COMMANDS;
private static final String INSTALL_LOCATION_PROVIDER =
@@ -182,7 +182,7 @@
private ActivityManager mActivityManager;
private UserManager mUserManager;
private GeocoderProxy mGeocodeProvider;
- private IGnssStatusProvider mGnssStatusProvider;
+ private GnssStatusListenerHelper mGnssStatusProvider;
private INetInitiatedListener mNetInitiatedListener;
private LocationWorkerHandler mLocationHandler;
private PassiveProvider mPassiveProvider; // track passive provider for special cases
@@ -192,12 +192,6 @@
private IGpsGeofenceHardware mGpsGeofenceProxy;
// --- fields below are protected by mLock ---
- // Set of providers that are explicitly enabled
- // Only used by passive, fused & test. Network & GPS are controlled separately, and not listed.
- private final Set<String> mEnabledProviders = new HashSet<>();
-
- // Set of providers that are explicitly disabled
- private final Set<String> mDisabledProviders = new HashSet<>();
// Mock (test) providers
private final HashMap<String, MockProvider> mMockProviders =
@@ -207,15 +201,15 @@
private final HashMap<Object, Receiver> mReceivers = new HashMap<>();
// currently installed providers (with mocks replacing real providers)
- private final ArrayList<LocationProviderInterface> mProviders =
+ private final ArrayList<LocationProvider> mProviders =
new ArrayList<>();
// real providers, saved here when mocked out
- private final HashMap<String, LocationProviderInterface> mRealProviders =
+ private final HashMap<String, LocationProvider> mRealProviders =
new HashMap<>();
// mapping from provider name to provider
- private final HashMap<String, LocationProviderInterface> mProvidersByName =
+ private final HashMap<String, LocationProvider> mProvidersByName =
new HashMap<>();
// mapping from provider name to all its UpdateRecords
@@ -270,13 +264,8 @@
PackageManagerInternal packageManagerInternal = LocalServices.getService(
PackageManagerInternal.class);
packageManagerInternal.setLocationPackagesProvider(
- new PackageManagerInternal.PackagesProvider() {
- @Override
- public String[] getPackages(int userId) {
- return mContext.getResources().getStringArray(
- com.android.internal.R.array.config_locationProviderPackageNames);
- }
- });
+ userId -> mContext.getResources().getStringArray(
+ com.android.internal.R.array.config_locationProviderPackageNames));
if (D) Log.d(TAG, "Constructed");
@@ -321,30 +310,17 @@
mAppOps.startWatchingMode(AppOpsManager.OP_COARSE_LOCATION, null,
AppOpsManager.WATCH_FOREGROUND_CHANGES, callback);
- PackageManager.OnPermissionsChangedListener permissionListener
- = new PackageManager.OnPermissionsChangedListener() {
- @Override
- public void onPermissionsChanged(final int uid) {
- synchronized (mLock) {
- applyAllProviderRequirementsLocked();
- }
+ PackageManager.OnPermissionsChangedListener permissionListener = uid -> {
+ synchronized (mLock) {
+ applyAllProviderRequirementsLocked();
}
};
mPackageManager.addOnPermissionsChangeListener(permissionListener);
// listen for background/foreground changes
- ActivityManager.OnUidImportanceListener uidImportanceListener
- = new ActivityManager.OnUidImportanceListener() {
- @Override
- public void onUidImportance(final int uid, final int importance) {
- mLocationHandler.post(new Runnable() {
- @Override
- public void run() {
- onUidImportanceChanged(uid, importance);
- }
- });
- }
- };
+ ActivityManager.OnUidImportanceListener uidImportanceListener =
+ (uid, importance) -> mLocationHandler.post(
+ () -> onUidImportanceChanged(uid, importance));
mActivityManager.addOnUidImportanceListener(uidImportanceListener,
FOREGROUND_IMPORTANCE_CUTOFF);
@@ -356,7 +332,10 @@
// prepare providers
loadProvidersLocked();
- updateProvidersLocked();
+ updateProvidersSettingsLocked();
+ for (LocationProvider provider : mProviders) {
+ applyRequirementsLocked(provider.getName());
+ }
}
// listen for settings changes
@@ -366,7 +345,7 @@
@Override
public void onChange(boolean selfChange) {
synchronized (mLock) {
- updateProvidersLocked();
+ updateProvidersSettingsLocked();
}
}
}, UserHandle.USER_ALL);
@@ -377,7 +356,9 @@
@Override
public void onChange(boolean selfChange) {
synchronized (mLock) {
- updateProvidersLocked();
+ for (LocationProvider provider : mProviders) {
+ applyRequirementsLocked(provider.getName());
+ }
}
}
}, UserHandle.USER_ALL);
@@ -402,7 +383,9 @@
public void onChange(boolean selfChange) {
synchronized (mLock) {
updateBackgroundThrottlingWhitelistLocked();
- updateProvidersLocked();
+ for (LocationProvider provider : mProviders) {
+ applyRequirementsLocked(provider.getName());
+ }
}
}
}, UserHandle.USER_ALL);
@@ -414,7 +397,6 @@
intentFilter.addAction(Intent.ACTION_USER_SWITCHED);
intentFilter.addAction(Intent.ACTION_MANAGED_PROFILE_ADDED);
intentFilter.addAction(Intent.ACTION_MANAGED_PROFILE_REMOVED);
- intentFilter.addAction(Intent.ACTION_SHUTDOWN);
mContext.registerReceiverAsUser(new BroadcastReceiver() {
@Override
@@ -425,12 +407,6 @@
} else if (Intent.ACTION_MANAGED_PROFILE_ADDED.equals(action)
|| Intent.ACTION_MANAGED_PROFILE_REMOVED.equals(action)) {
updateUserProfiles(mCurrentUserId);
- } else if (Intent.ACTION_SHUTDOWN.equals(action)) {
- // shutdown only if UserId indicates whole system, not just one user
- if (D) Log.d(TAG, "Shutdown received with UserId: " + getSendingUserId());
- if (getSendingUserId() == UserHandle.USER_ALL) {
- shutdownComponents();
- }
}
}
}, UserHandle.ALL, intentFilter, null, mLocationHandler);
@@ -463,14 +439,16 @@
}
for (Entry<IBinder, Identity> entry : mGnssMeasurementsListeners.entrySet()) {
- if (entry.getValue().mUid == uid) {
+ Identity callerIdentity = entry.getValue();
+ if (callerIdentity.mUid == uid) {
if (D) {
Log.d(TAG, "gnss measurements listener from uid " + uid
+ " is now " + (foreground ? "foreground" : "background)"));
}
if (foreground || isThrottlingExemptLocked(entry.getValue())) {
mGnssMeasurementsProvider.addListener(
- IGnssMeasurementsListener.Stub.asInterface(entry.getKey()));
+ IGnssMeasurementsListener.Stub.asInterface(entry.getKey()),
+ callerIdentity.mUid, callerIdentity.mPackageName);
} else {
mGnssMeasurementsProvider.removeListener(
IGnssMeasurementsListener.Stub.asInterface(entry.getKey()));
@@ -479,7 +457,8 @@
}
for (Entry<IBinder, Identity> entry : mGnssNavigationMessageListeners.entrySet()) {
- if (entry.getValue().mUid == uid) {
+ Identity callerIdentity = entry.getValue();
+ if (callerIdentity.mUid == uid) {
if (D) {
Log.d(TAG, "gnss navigation message listener from uid "
+ uid + " is now "
@@ -487,13 +466,16 @@
}
if (foreground || isThrottlingExemptLocked(entry.getValue())) {
mGnssNavigationMessageProvider.addListener(
- IGnssNavigationMessageListener.Stub.asInterface(entry.getKey()));
+ IGnssNavigationMessageListener.Stub.asInterface(entry.getKey()),
+ callerIdentity.mUid, callerIdentity.mPackageName);
} else {
mGnssNavigationMessageProvider.removeListener(
IGnssNavigationMessageListener.Stub.asInterface(entry.getKey()));
}
}
}
+
+ // TODO(b/120449926): The GNSS status listeners should be handled similar to the above.
}
}
@@ -502,30 +484,13 @@
}
/**
- * Provides a way for components held by the {@link LocationManagerService} to clean-up
- * gracefully on system's shutdown.
- *
- * NOTES:
- * 1) Only provides a chance to clean-up on an opt-in basis. This guarantees back-compat
- * support for components that do not wish to handle such event.
- */
- private void shutdownComponents() {
- if (D) Log.d(TAG, "Shutting down components...");
-
- LocationProviderInterface gpsProvider = mProvidersByName.get(LocationManager.GPS_PROVIDER);
- if (gpsProvider != null && gpsProvider.isEnabled()) {
- gpsProvider.disable();
- }
- }
-
- /**
* Makes a list of userids that are related to the current user. This is
* relevant when using managed profiles. Otherwise the list only contains
* the current user.
*
* @param currentUserId the current user, who might have an alter-ego.
*/
- void updateUserProfiles(int currentUserId) {
+ private void updateUserProfiles(int currentUserId) {
int[] profileIds = mUserManager.getProfileIdsWithDisabled(currentUserId);
synchronized (mLock) {
mCurrentUserProfiles = profileIds;
@@ -614,22 +579,28 @@
private void loadProvidersLocked() {
// create a passive location provider, which is always enabled
- PassiveProvider passiveProvider = new PassiveProvider(this);
- addProviderLocked(passiveProvider);
- mEnabledProviders.add(passiveProvider.getName());
+ LocationProvider passiveProviderManager = new LocationProvider(
+ LocationManager.PASSIVE_PROVIDER);
+ PassiveProvider passiveProvider = new PassiveProvider(passiveProviderManager);
+
+ addProviderLocked(passiveProviderManager);
mPassiveProvider = passiveProvider;
if (GnssLocationProvider.isSupported()) {
// Create a gps location provider
- GnssLocationProvider gnssProvider = new GnssLocationProvider(mContext, this,
+ LocationProvider gnssProviderManager = new LocationProvider(
+ LocationManager.GPS_PROVIDER);
+ GnssLocationProvider gnssProvider = new GnssLocationProvider(mContext,
+ gnssProviderManager,
mLocationHandler.getLooper());
+
mGnssSystemInfoProvider = gnssProvider.getGnssSystemInfoProvider();
mGnssBatchingProvider = gnssProvider.getGnssBatchingProvider();
mGnssMetricsProvider = gnssProvider.getGnssMetricsProvider();
mGnssStatusProvider = gnssProvider.getGnssStatusProvider();
mNetInitiatedListener = gnssProvider.getNetInitiatedListener();
- addProviderLocked(gnssProvider);
- mRealProviders.put(LocationManager.GPS_PROVIDER, gnssProvider);
+ addProviderLocked(gnssProviderManager);
+ mRealProviders.put(LocationManager.GPS_PROVIDER, gnssProviderManager);
mGnssMeasurementsProvider = gnssProvider.getGnssMeasurementsProvider();
mGnssNavigationMessageProvider = gnssProvider.getGnssNavigationMessageProvider();
mGpsGeofenceProxy = gnssProvider.getGpsGeofenceProxy();
@@ -657,34 +628,38 @@
ensureFallbackFusedProviderPresentLocked(pkgs);
// bind to network provider
+
+ LocationProvider networkProviderManager = new LocationProvider(
+ LocationManager.NETWORK_PROVIDER);
LocationProviderProxy networkProvider = LocationProviderProxy.createAndBind(
mContext,
- LocationManager.NETWORK_PROVIDER,
+ networkProviderManager,
NETWORK_LOCATION_SERVICE_ACTION,
com.android.internal.R.bool.config_enableNetworkLocationOverlay,
com.android.internal.R.string.config_networkLocationProviderPackageName,
com.android.internal.R.array.config_locationProviderPackageNames);
if (networkProvider != null) {
- mRealProviders.put(LocationManager.NETWORK_PROVIDER, networkProvider);
+ mRealProviders.put(LocationManager.NETWORK_PROVIDER, networkProviderManager);
mProxyProviders.add(networkProvider);
- addProviderLocked(networkProvider);
+ addProviderLocked(networkProviderManager);
} else {
Slog.w(TAG, "no network location provider found");
}
// bind to fused provider
- LocationProviderProxy fusedLocationProvider = LocationProviderProxy.createAndBind(
+ LocationProvider fusedProviderManager = new LocationProvider(
+ LocationManager.FUSED_PROVIDER);
+ LocationProviderProxy fusedProvider = LocationProviderProxy.createAndBind(
mContext,
- LocationManager.FUSED_PROVIDER,
+ fusedProviderManager,
FUSED_LOCATION_SERVICE_ACTION,
com.android.internal.R.bool.config_enableFusedLocationOverlay,
com.android.internal.R.string.config_fusedLocationProviderPackageName,
com.android.internal.R.array.config_locationProviderPackageNames);
- if (fusedLocationProvider != null) {
- addProviderLocked(fusedLocationProvider);
- mProxyProviders.add(fusedLocationProvider);
- mEnabledProviders.add(fusedLocationProvider.getName());
- mRealProviders.put(LocationManager.FUSED_PROVIDER, fusedLocationProvider);
+ if (fusedProvider != null) {
+ addProviderLocked(fusedProviderManager);
+ mProxyProviders.add(fusedProvider);
+ mRealProviders.put(LocationManager.FUSED_PROVIDER, fusedProviderManager);
} else {
Slog.e(TAG, "no fused location provider found",
new IllegalStateException("Location service needs a fused location provider"));
@@ -765,12 +740,9 @@
synchronized (mLock) {
mLastLocation.clear();
mLastLocationCoarseInterval.clear();
- for (LocationProviderInterface p : mProviders) {
- updateProviderListenersLocked(p.getName(), false);
- }
- mCurrentUserId = userId;
updateUserProfiles(userId);
- updateProvidersLocked();
+ updateProvidersSettingsLocked();
+ mCurrentUserId = userId;
}
}
@@ -786,6 +758,165 @@
}
}
+ private class LocationProvider implements AbstractLocationProvider.LocationProviderManager {
+
+ private final String mName;
+ private AbstractLocationProvider mProvider;
+
+ // whether the provider is enabled in location settings
+ private boolean mSettingsEnabled;
+
+ // whether the provider considers itself enabled
+ private volatile boolean mEnabled;
+
+ @Nullable
+ private volatile ProviderProperties mProperties;
+
+ private LocationProvider(String name) {
+ mName = name;
+ // TODO: initialize settings enabled?
+ }
+
+ @Override
+ public void onAttachProvider(AbstractLocationProvider provider, boolean initiallyEnabled) {
+ checkState(mProvider == null);
+
+ // the provider is not yet fully constructed at this point, so we may not do anything
+ // except save a reference for later use here. do not call any provider methods.
+ mProvider = provider;
+ mEnabled = initiallyEnabled;
+ mProperties = null;
+ }
+
+ public String getName() {
+ return mName;
+ }
+
+ public boolean isEnabled() {
+ return mSettingsEnabled && mEnabled;
+ }
+
+ @Nullable
+ public ProviderProperties getProperties() {
+ return mProperties;
+ }
+
+ public void setRequest(ProviderRequest request, WorkSource workSource) {
+ mProvider.setRequest(request, workSource);
+ }
+
+ public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
+ pw.println(mName + " provider:");
+ pw.println(" setting=" + mSettingsEnabled);
+ pw.println(" enabled=" + mEnabled);
+ pw.println(" properties=" + mProperties);
+ mProvider.dump(fd, pw, args);
+ }
+
+ public long getStatusUpdateTime() {
+ return mProvider.getStatusUpdateTime();
+ }
+
+ public int getStatus(Bundle extras) {
+ return mProvider.getStatus(extras);
+ }
+
+ public void sendExtraCommand(String command, Bundle extras) {
+ mProvider.sendExtraCommand(command, extras);
+ }
+
+ // called from any thread
+ @Override
+ public void onReportLocation(Location location) {
+ runOnHandler(() -> LocationManagerService.this.reportLocation(location,
+ mProvider == mPassiveProvider));
+ }
+
+ // called from any thread
+ @Override
+ public void onReportLocation(List<Location> locations) {
+ runOnHandler(() -> LocationManagerService.this.reportLocationBatch(locations));
+ }
+
+ // called from any thread
+ @Override
+ public void onSetEnabled(boolean enabled) {
+ runOnHandler(() -> {
+ if (enabled == mEnabled) {
+ return;
+ }
+
+ mEnabled = enabled;
+
+ if (!mSettingsEnabled) {
+ // this provider was disabled in settings anyways, so a change to it's own
+ // enabled status won't have any affect.
+ return;
+ }
+
+ // traditionally clients can listen for changes to the LOCATION_PROVIDERS_ALLOWED
+ // setting to detect when providers are enabled or disabled (even though they aren't
+ // supposed to). to continue to support this we must force a change to this setting.
+ // we use the fused provider because this is forced to be always enabled in settings
+ // anyways, and so won't have any visible effect beyond triggering content observers
+ Settings.Secure.putStringForUser(mContext.getContentResolver(),
+ Settings.Secure.LOCATION_PROVIDERS_ALLOWED,
+ "+" + LocationManager.FUSED_PROVIDER, mCurrentUserId);
+ Settings.Secure.putStringForUser(mContext.getContentResolver(),
+ Settings.Secure.LOCATION_PROVIDERS_ALLOWED,
+ "-" + LocationManager.FUSED_PROVIDER, mCurrentUserId);
+
+ synchronized (mLock) {
+ if (!enabled) {
+ // If any provider has been disabled, clear all last locations for all
+ // providers. This is to be on the safe side in case a provider has location
+ // derived from this disabled provider.
+ mLastLocation.clear();
+ mLastLocationCoarseInterval.clear();
+ }
+
+ updateProviderListenersLocked(mName);
+ }
+
+ mContext.sendBroadcastAsUser(new Intent(LocationManager.PROVIDERS_CHANGED_ACTION),
+ UserHandle.ALL);
+ });
+ }
+
+ @Override
+ public void onSetProperties(ProviderProperties properties) {
+ runOnHandler(() -> mProperties = properties);
+ }
+
+ private void setSettingsEnabled(boolean enabled) {
+ synchronized (mLock) {
+ if (mSettingsEnabled == enabled) {
+ return;
+ }
+
+ mSettingsEnabled = enabled;
+ if (!mSettingsEnabled) {
+ // if any provider has been disabled, clear all last locations for all
+ // providers. this is to be on the safe side in case a provider has location
+ // derived from this disabled provider.
+ mLastLocation.clear();
+ mLastLocationCoarseInterval.clear();
+ updateProviderListenersLocked(mName);
+ } else if (mEnabled) {
+ updateProviderListenersLocked(mName);
+ }
+ }
+ }
+
+ private void runOnHandler(Runnable runnable) {
+ if (Looper.myLooper() == mLocationHandler.getLooper()) {
+ runnable.run();
+ } else {
+ mLocationHandler.post(runnable);
+ }
+ }
+ }
+
/**
* A wrapper class holding either an ILocationListener or a PendingIntent to receive
* location updates.
@@ -793,24 +924,24 @@
private final class Receiver implements IBinder.DeathRecipient, PendingIntent.OnFinished {
private static final long WAKELOCK_TIMEOUT_MILLIS = 60 * 1000;
final Identity mIdentity;
- final int mAllowedResolutionLevel; // resolution level allowed to receiver
+ private final int mAllowedResolutionLevel; // resolution level allowed to receiver
- final ILocationListener mListener;
+ private final ILocationListener mListener;
final PendingIntent mPendingIntent;
final WorkSource mWorkSource; // WorkSource for battery blame, or null to assign to caller.
- final boolean mHideFromAppOps; // True if AppOps should not monitor this receiver.
- final Object mKey;
+ private final boolean mHideFromAppOps; // True if AppOps should not monitor this receiver.
+ private final Object mKey;
final HashMap<String, UpdateRecord> mUpdateRecords = new HashMap<>();
// True if app ops has started monitoring this receiver for locations.
- boolean mOpMonitoring;
+ private boolean mOpMonitoring;
// True if app ops has started monitoring this receiver for high power (gps) locations.
- boolean mOpHighPowerMonitoring;
- int mPendingBroadcasts;
+ private boolean mOpHighPowerMonitoring;
+ private int mPendingBroadcasts;
PowerManager.WakeLock mWakeLock;
- Receiver(ILocationListener listener, PendingIntent intent, int pid, int uid,
+ private Receiver(ILocationListener listener, PendingIntent intent, int pid, int uid,
String packageName, WorkSource workSource, boolean hideFromAppOps) {
mListener = listener;
mPendingIntent = intent;
@@ -885,9 +1016,10 @@
// See if receiver has any enabled update records. Also note if any update records
// are high power (has a high power provider with an interval under a threshold).
for (UpdateRecord updateRecord : mUpdateRecords.values()) {
- if (isAllowedByCurrentUserSettingsLocked(updateRecord.mProvider)) {
+ if (isAllowedByUserSettingsLockedForUser(updateRecord.mProvider,
+ mCurrentUserId)) {
requestingLocation = true;
- LocationProviderInterface locationProvider
+ LocationManagerService.LocationProvider locationProvider
= mProvidersByName.get(updateRecord.mProvider);
ProviderProperties properties = locationProvider != null
? locationProvider.getProperties() : null;
@@ -1034,7 +1166,7 @@
return true;
}
- public boolean callProviderEnabledLocked(String provider, boolean enabled) {
+ private boolean callProviderEnabledLocked(String provider, boolean enabled) {
// First update AppOp monitoring.
// An app may get/lose location access as providers are enabled/disabled.
updateMonitoring(true);
@@ -1236,7 +1368,7 @@
private class LinkedCallback implements IBinder.DeathRecipient {
private final IBatchedLocationCallback mCallback;
- public LinkedCallback(@NonNull IBatchedLocationCallback callback) {
+ private LinkedCallback(@NonNull IBatchedLocationCallback callback) {
mCallback = callback;
}
@@ -1337,7 +1469,7 @@
checkCallerIsProvider();
// Currently used only for GNSS locations - update permissions check if changed
- if (isAllowedByCurrentUserSettingsLocked(LocationManager.GPS_PROVIDER)) {
+ if (isAllowedByUserSettingsLockedForUser(LocationManager.GPS_PROVIDER, mCurrentUserId)) {
if (mGnssBatchingCallback == null) {
Slog.e(TAG, "reportLocationBatch() called without active Callback");
return;
@@ -1352,29 +1484,17 @@
}
}
- private void addProviderLocked(LocationProviderInterface provider) {
+ private void addProviderLocked(LocationProvider provider) {
mProviders.add(provider);
mProvidersByName.put(provider.getName(), provider);
}
- private void removeProviderLocked(LocationProviderInterface provider) {
- provider.disable();
+ private void removeProviderLocked(LocationProvider provider) {
mProviders.remove(provider);
mProvidersByName.remove(provider.getName());
}
/**
- * Returns "true" if access to the specified location provider is allowed by the current
- * user's settings. Access to all location providers is forbidden to non-location-provider
- * processes belonging to background users.
- *
- * @param provider the name of the location provider
- */
- private boolean isAllowedByCurrentUserSettingsLocked(String provider) {
- return isAllowedByUserSettingsLockedForUser(provider, mCurrentUserId);
- }
-
- /**
* Returns "true" if access to the specified location provider is allowed by the specified
* user's settings. Access to all location providers is forbidden to non-location-provider
* processes belonging to background users.
@@ -1383,13 +1503,28 @@
* @param userId the user id to query
*/
private boolean isAllowedByUserSettingsLockedForUser(String provider, int userId) {
- if (mEnabledProviders.contains(provider)) {
- return true;
+ if (LocationManager.PASSIVE_PROVIDER.equals(provider)) {
+ return isLocationEnabledForUser(userId);
}
- if (mDisabledProviders.contains(provider)) {
- return false;
+ if (LocationManager.FUSED_PROVIDER.equals(provider)) {
+ return isLocationEnabledForUser(userId);
}
- return isLocationProviderEnabledForUser(provider, userId);
+ synchronized (mLock) {
+ if (mMockProviders.containsKey(provider)) {
+ return isLocationEnabledForUser(userId);
+ }
+ }
+
+ long identity = Binder.clearCallingIdentity();
+ try {
+ // Use system settings
+ ContentResolver cr = mContext.getContentResolver();
+ String allowedProviders = Settings.Secure.getStringForUser(
+ cr, Settings.Secure.LOCATION_PROVIDERS_ALLOWED, userId);
+ return TextUtils.delimitedStringContains(allowedProviders, ',', provider);
+ } finally {
+ Binder.restoreCallingIdentity(identity);
+ }
}
@@ -1481,9 +1616,11 @@
// network and fused providers are ok with COARSE or FINE
return RESOLUTION_LEVEL_COARSE;
} else {
- // mock providers
- LocationProviderInterface lp = mMockProviders.get(provider);
- if (lp != null) {
+ for (LocationProvider lp : mProviders) {
+ if (!lp.getName().equals(provider)) {
+ continue;
+ }
+
ProviderProperties properties = lp.getProperties();
if (properties != null) {
if (properties.mRequiresSatellite) {
@@ -1496,6 +1633,7 @@
}
}
}
+
return RESOLUTION_LEVEL_FINE; // if in doubt, require FINE
}
@@ -1550,7 +1688,7 @@
}
private static String resolutionLevelToOpStr(int allowedResolutionLevel) {
- switch(allowedResolutionLevel) {
+ switch (allowedResolutionLevel) {
case RESOLUTION_LEVEL_COARSE:
return AppOpsManager.OPSTR_COARSE_LOCATION;
case RESOLUTION_LEVEL_FINE:
@@ -1565,7 +1703,7 @@
}
}
- boolean reportLocationAccessNoThrow(
+ private boolean reportLocationAccessNoThrow(
int pid, int uid, String packageName, int allowedResolutionLevel) {
int op = resolutionLevelToOp(allowedResolutionLevel);
if (op >= 0) {
@@ -1577,7 +1715,8 @@
return getAllowedResolutionLevel(pid, uid) >= allowedResolutionLevel;
}
- boolean checkLocationAccess(int pid, int uid, String packageName, int allowedResolutionLevel) {
+ private boolean checkLocationAccess(int pid, int uid, String packageName,
+ int allowedResolutionLevel) {
int op = resolutionLevelToOp(allowedResolutionLevel);
if (op >= 0) {
if (mAppOps.noteOp(op, uid, packageName) != AppOpsManager.MODE_ALLOWED) {
@@ -1597,7 +1736,7 @@
ArrayList<String> out;
synchronized (mLock) {
out = new ArrayList<>(mProviders.size());
- for (LocationProviderInterface provider : mProviders) {
+ for (LocationProvider provider : mProviders) {
String name = provider.getName();
if (LocationManager.FUSED_PROVIDER.equals(name)) {
continue;
@@ -1623,7 +1762,7 @@
try {
synchronized (mLock) {
out = new ArrayList<>(mProviders.size());
- for (LocationProviderInterface provider : mProviders) {
+ for (LocationProvider provider : mProviders) {
String name = provider.getName();
if (LocationManager.FUSED_PROVIDER.equals(name)) {
continue;
@@ -1633,7 +1772,8 @@
&& !isAllowedByUserSettingsLocked(name, uid, mCurrentUserId)) {
continue;
}
- if (criteria != null && !LocationProvider.propertiesMeetCriteria(
+ if (criteria != null
+ && !android.location.LocationProvider.propertiesMeetCriteria(
name, provider.getProperties(), criteria)) {
continue;
}
@@ -1658,7 +1798,7 @@
*/
@Override
public String getBestProvider(Criteria criteria, boolean enabledOnly) {
- String result = null;
+ String result;
List<String> providers = getProviders(criteria, enabledOnly);
if (!providers.isEmpty()) {
@@ -1673,7 +1813,7 @@
return result;
}
- if (D) Log.d(TAG, "getBestProvider(" + criteria + ", " + enabledOnly + ")=" + result);
+ if (D) Log.d(TAG, "getBestProvider(" + criteria + ", " + enabledOnly + ")=" + null);
return null;
}
@@ -1689,51 +1829,32 @@
@Override
public boolean providerMeetsCriteria(String provider, Criteria criteria) {
- LocationProviderInterface p = mProvidersByName.get(provider);
+ LocationProvider p = mProvidersByName.get(provider);
if (p == null) {
throw new IllegalArgumentException("provider=" + provider);
}
- boolean result = LocationProvider.propertiesMeetCriteria(
+ boolean result = android.location.LocationProvider.propertiesMeetCriteria(
p.getName(), p.getProperties(), criteria);
if (D) Log.d(TAG, "providerMeetsCriteria(" + provider + ", " + criteria + ")=" + result);
return result;
}
- private void updateProvidersLocked() {
- boolean changesMade = false;
- for (int i = mProviders.size() - 1; i >= 0; i--) {
- LocationProviderInterface p = mProviders.get(i);
- boolean isEnabled = p.isEnabled();
- String name = p.getName();
- boolean shouldBeEnabled = isAllowedByCurrentUserSettingsLocked(name);
- if (isEnabled && !shouldBeEnabled) {
- updateProviderListenersLocked(name, false);
- // If any provider has been disabled, clear all last locations for all providers.
- // This is to be on the safe side in case a provider has location derived from
- // this disabled provider.
- mLastLocation.clear();
- mLastLocationCoarseInterval.clear();
- changesMade = true;
- } else if (!isEnabled && shouldBeEnabled) {
- updateProviderListenersLocked(name, true);
- changesMade = true;
- }
+ private void updateProvidersSettingsLocked() {
+ for (LocationProvider p : mProviders) {
+ p.setSettingsEnabled(isAllowedByUserSettingsLockedForUser(p.getName(), mCurrentUserId));
}
- if (changesMade) {
- mContext.sendBroadcastAsUser(new Intent(LocationManager.PROVIDERS_CHANGED_ACTION),
- UserHandle.ALL);
- mContext.sendBroadcastAsUser(new Intent(LocationManager.MODE_CHANGED_ACTION),
- UserHandle.ALL);
- }
+
+ mContext.sendBroadcastAsUser(new Intent(LocationManager.MODE_CHANGED_ACTION),
+ UserHandle.ALL);
}
- private void updateProviderListenersLocked(String provider, boolean enabled) {
- int listeners = 0;
-
- LocationProviderInterface p = mProvidersByName.get(provider);
+ private void updateProviderListenersLocked(String provider) {
+ LocationProvider p = mProvidersByName.get(provider);
if (p == null) return;
+ boolean enabled = p.isEnabled();
+
ArrayList<Receiver> deadReceivers = null;
ArrayList<UpdateRecord> records = mRecordsByProvider.get(provider);
@@ -1747,7 +1868,6 @@
}
deadReceivers.add(record.mReceiver);
}
- listeners++;
}
}
}
@@ -1758,16 +1878,11 @@
}
}
- if (enabled) {
- p.enable();
- applyRequirementsLocked(provider);
- } else {
- p.disable();
- }
+ applyRequirementsLocked(provider);
}
private void applyRequirementsLocked(String provider) {
- LocationProviderInterface p = mProvidersByName.get(provider);
+ LocationProvider p = mProvidersByName.get(provider);
if (p == null) return;
ArrayList<UpdateRecord> records = mRecordsByProvider.get(provider);
@@ -1779,10 +1894,10 @@
resolver,
Settings.Global.LOCATION_BACKGROUND_THROTTLE_INTERVAL_MS,
DEFAULT_BACKGROUND_THROTTLE_INTERVAL_MS);
- // initialize the low power mode to true and set to false if any of the records requires
- providerRequest.lowPowerMode = true;
- if (records != null) {
+ if (p.isEnabled() && records != null && !records.isEmpty()) {
+ // initialize the low power mode to true and set to false if any of the records requires
+ providerRequest.lowPowerMode = true;
for (UpdateRecord record : records) {
if (isCurrentProfile(UserHandle.getUserId(record.mReceiver.mIdentity.mUid))) {
if (checkLocationAccess(
@@ -1875,7 +1990,7 @@
public String[] getBackgroundThrottlingWhitelist() {
synchronized (mLock) {
return mBackgroundThrottlePackageWhitelist.toArray(
- new String[mBackgroundThrottlePackageWhitelist.size()]);
+ new String[0]);
}
}
@@ -1922,17 +2037,17 @@
private class UpdateRecord {
final String mProvider;
- final LocationRequest mRealRequest; // original request from client
+ private final LocationRequest mRealRequest; // original request from client
LocationRequest mRequest; // possibly throttled version of the request
- final Receiver mReceiver;
- boolean mIsForegroundUid;
- Location mLastFixBroadcast;
- long mLastStatusBroadcast;
+ private final Receiver mReceiver;
+ private boolean mIsForegroundUid;
+ private Location mLastFixBroadcast;
+ private long mLastStatusBroadcast;
/**
* Note: must be constructed with lock held.
*/
- UpdateRecord(String provider, LocationRequest request, Receiver receiver) {
+ private UpdateRecord(String provider, LocationRequest request, Receiver receiver) {
mProvider = provider;
mRealRequest = request;
mRequest = request;
@@ -1958,7 +2073,7 @@
/**
* Method to be called when record changes foreground/background
*/
- void updateForeground(boolean isForeground){
+ private void updateForeground(boolean isForeground) {
mIsForegroundUid = isForeground;
mRequestStatistics.updateForeground(
mReceiver.mIdentity.mPackageName, mProvider, isForeground);
@@ -1967,7 +2082,7 @@
/**
* Method to be called when a record will no longer be used.
*/
- void disposeLocked(boolean removeReceiver) {
+ private void disposeLocked(boolean removeReceiver) {
mRequestStatistics.stopRequesting(mReceiver.mIdentity.mPackageName, mProvider);
// remove from mRecordsByProvider
@@ -1980,13 +2095,11 @@
// remove from Receiver#mUpdateRecords
HashMap<String, UpdateRecord> receiverRecords = mReceiver.mUpdateRecords;
- if (receiverRecords != null) {
- receiverRecords.remove(this.mProvider);
+ receiverRecords.remove(this.mProvider);
- // and also remove the Receiver if it has no more update records
- if (receiverRecords.size() == 0) {
- removeUpdatesLocked(mReceiver);
- }
+ // and also remove the Receiver if it has no more update records
+ if (receiverRecords.size() == 0) {
+ removeUpdatesLocked(mReceiver);
}
}
@@ -2070,7 +2183,7 @@
private void checkPackageName(String packageName) {
if (packageName == null) {
- throw new SecurityException("invalid package name: " + packageName);
+ throw new SecurityException("invalid package name: " + null);
}
int uid = Binder.getCallingUid();
String[] packages = mPackageManager.getPackagesForUid(uid);
@@ -2085,7 +2198,7 @@
private void checkPendingIntent(PendingIntent intent) {
if (intent == null) {
- throw new IllegalArgumentException("invalid pending intent: " + intent);
+ throw new IllegalArgumentException("invalid pending intent: " + null);
}
}
@@ -2137,7 +2250,7 @@
synchronized (mLock) {
Receiver recevier = checkListenerOrIntentLocked(listener, intent, pid, uid,
packageName, workSource, hideFromAppOps);
- requestLocationUpdatesLocked(sanitizedRequest, recevier, pid, uid, packageName);
+ requestLocationUpdatesLocked(sanitizedRequest, recevier, uid, packageName);
}
} finally {
Binder.restoreCallingIdentity(identity);
@@ -2145,7 +2258,7 @@
}
private void requestLocationUpdatesLocked(LocationRequest request, Receiver receiver,
- int pid, int uid, String packageName) {
+ int uid, String packageName) {
// Figure out the provider. Either its explicitly request (legacy use cases), or
// use the fused provider
if (request == null) request = DEFAULT_LOCATION_REQUEST;
@@ -2154,7 +2267,7 @@
throw new IllegalArgumentException("provider name must not be null");
}
- LocationProviderInterface provider = mProvidersByName.get(name);
+ LocationProvider provider = mProvidersByName.get(name);
if (provider == null) {
throw new IllegalArgumentException("provider doesn't exist: " + name);
}
@@ -2173,8 +2286,7 @@
oldRecord.disposeLocked(false);
}
- boolean isProviderEnabled = isAllowedByUserSettingsLocked(name, uid, mCurrentUserId);
- if (isProviderEnabled) {
+ if (provider.isEnabled()) {
applyRequirementsLocked(name);
} else {
// Notify the listener that updates are currently disabled
@@ -2194,10 +2306,8 @@
final int uid = Binder.getCallingUid();
synchronized (mLock) {
- WorkSource workSource = null;
- boolean hideFromAppOps = false;
Receiver receiver = checkListenerOrIntentLocked(listener, intent, pid, uid,
- packageName, workSource, hideFromAppOps);
+ packageName, null, false);
// providers may use public location API's, need to clear identity
long identity = Binder.clearCallingIdentity();
@@ -2236,22 +2346,12 @@
// update provider
for (String provider : providers) {
- // If provider is already disabled, don't need to do anything
- if (!isAllowedByCurrentUserSettingsLocked(provider)) {
- continue;
- }
-
applyRequirementsLocked(provider);
}
}
private void applyAllProviderRequirementsLocked() {
- for (LocationProviderInterface p : mProviders) {
- // If provider is already disabled, don't need to do anything
- if (!isAllowedByCurrentUserSettingsLocked(p.getName())) {
- continue;
- }
-
+ for (LocationProvider p : mProviders) {
applyRequirementsLocked(p.getName());
}
}
@@ -2291,7 +2391,7 @@
// or use the fused provider
String name = request.getProvider();
if (name == null) name = LocationManager.FUSED_PROVIDER;
- LocationProviderInterface provider = mProvidersByName.get(name);
+ LocationProvider provider = mProvidersByName.get(name);
if (provider == null) return null;
if (!isAllowedByUserSettingsLocked(name, uid, mCurrentUserId)) return null;
@@ -2314,7 +2414,7 @@
location.getElapsedRealtimeNanos() / NANOS_PER_MILLI;
if ((locationAgeMs > mLastLocationMaxAgeMs)
&& (mAppOps.unsafeCheckOp(op, uid, packageName)
- == AppOpsManager.MODE_FOREGROUND)) {
+ == AppOpsManager.MODE_FOREGROUND)) {
return null;
}
@@ -2358,7 +2458,7 @@
}
return false;
}
- LocationProviderInterface p = null;
+ LocationProvider p = null;
String provider = location.getProvider();
if (provider != null) {
p = mProvidersByName.get(provider);
@@ -2370,7 +2470,7 @@
return false;
}
synchronized (mLock) {
- if (!isAllowedByCurrentUserSettingsLocked(provider)) {
+ if (!isAllowedByUserSettingsLockedForUser(provider, mCurrentUserId)) {
if (D) {
Log.d(TAG, "Location disabled in Settings for current user:" + mCurrentUserId);
}
@@ -2444,31 +2544,20 @@
}
}
-
@Override
public boolean registerGnssStatusCallback(IGnssStatusListener callback, String packageName) {
if (!hasGnssPermissions(packageName) || mGnssStatusProvider == null) {
return false;
}
- try {
- mGnssStatusProvider.registerGnssStatusCallback(callback);
- } catch (RemoteException e) {
- Slog.e(TAG, "mGpsStatusProvider.registerGnssStatusCallback failed", e);
- return false;
- }
- return true;
+ // TODO(b/120449926): The GNSS status listeners should be handled similar to the GNSS
+ // measurements listeners.
+ return mGnssStatusProvider.addListener(callback, Binder.getCallingUid(), packageName);
}
@Override
public void unregisterGnssStatusCallback(IGnssStatusListener callback) {
- synchronized (mLock) {
- try {
- mGnssStatusProvider.unregisterGnssStatusCallback(callback);
- } catch (Exception e) {
- Slog.e(TAG, "mGpsStatusProvider.unregisterGnssStatusCallback failed", e);
- }
- }
+ mGnssStatusProvider.removeListener(callback);
}
@Override
@@ -2481,13 +2570,15 @@
synchronized (mLock) {
Identity callerIdentity
= new Identity(Binder.getCallingUid(), Binder.getCallingPid(), packageName);
+ // TODO(b/120481270): Register for client death notification and update map.
mGnssMeasurementsListeners.put(listener.asBinder(), callerIdentity);
long identity = Binder.clearCallingIdentity();
try {
if (isThrottlingExemptLocked(callerIdentity)
|| isImportanceForeground(
mActivityManager.getPackageImportance(packageName))) {
- return mGnssMeasurementsProvider.addListener(listener);
+ return mGnssMeasurementsProvider.addListener(listener,
+ callerIdentity.mUid, callerIdentity.mPackageName);
}
} finally {
Binder.restoreCallingIdentity(identity);
@@ -2499,11 +2590,13 @@
@Override
public void removeGnssMeasurementsListener(IGnssMeasurementsListener listener) {
- if (mGnssMeasurementsProvider != null) {
- synchronized (mLock) {
- mGnssMeasurementsListeners.remove(listener.asBinder());
- mGnssMeasurementsProvider.removeListener(listener);
- }
+ if (mGnssMeasurementsProvider == null) {
+ return;
+ }
+
+ synchronized (mLock) {
+ mGnssMeasurementsListeners.remove(listener.asBinder());
+ mGnssMeasurementsProvider.removeListener(listener);
}
}
@@ -2518,13 +2611,15 @@
synchronized (mLock) {
Identity callerIdentity
= new Identity(Binder.getCallingUid(), Binder.getCallingPid(), packageName);
+ // TODO(b/120481270): Register for client death notification and update map.
mGnssNavigationMessageListeners.put(listener.asBinder(), callerIdentity);
long identity = Binder.clearCallingIdentity();
try {
if (isThrottlingExemptLocked(callerIdentity)
|| isImportanceForeground(
mActivityManager.getPackageImportance(packageName))) {
- return mGnssNavigationMessageProvider.addListener(listener);
+ return mGnssNavigationMessageProvider.addListener(listener,
+ callerIdentity.mUid, callerIdentity.mPackageName);
}
} finally {
Binder.restoreCallingIdentity(identity);
@@ -2560,10 +2655,11 @@
}
synchronized (mLock) {
- LocationProviderInterface p = mProvidersByName.get(provider);
+ LocationProvider p = mProvidersByName.get(provider);
if (p == null) return false;
- return p.sendExtraCommand(command, extras);
+ p.sendExtraCommand(command, extras);
+ return true;
}
}
@@ -2588,14 +2684,10 @@
*/
@Override
public ProviderProperties getProviderProperties(String provider) {
- if (mProvidersByName.get(provider) == null) {
- return null;
- }
-
checkResolutionLevelIsSufficientForProviderUse(getCallerAllowedResolutionLevel(),
provider);
- LocationProviderInterface p;
+ LocationProvider p;
synchronized (mLock) {
p = mProvidersByName.get(provider);
}
@@ -2611,25 +2703,25 @@
*/
@Override
public String getNetworkProviderPackage() {
- LocationProviderInterface p;
+ LocationProvider p;
synchronized (mLock) {
- if (mProvidersByName.get(LocationManager.NETWORK_PROVIDER) == null) {
- return null;
- }
p = mProvidersByName.get(LocationManager.NETWORK_PROVIDER);
}
- if (p instanceof LocationProviderProxy) {
- return ((LocationProviderProxy) p).getConnectedPackageName();
+ if (p == null) {
+ return null;
+ }
+ if (p.mProvider instanceof LocationProviderProxy) {
+ return ((LocationProviderProxy) p.mProvider).getConnectedPackageName();
}
return null;
}
/**
- * Returns the current location enabled/disabled status for a user
+ * Returns the current location enabled/disabled status for a user
*
- * @param userId the id of the user
- * @return true if location is enabled
+ * @param userId the id of the user
+ * @return true if location is enabled
*/
@Override
public boolean isLocationEnabledForUser(int userId) {
@@ -2647,7 +2739,7 @@
return false;
}
final List<String> providerList = Arrays.asList(allowedProviders.split(","));
- for(String provider : mRealProviders.keySet()) {
+ for (String provider : mRealProviders.keySet()) {
if (provider.equals(LocationManager.PASSIVE_PROVIDER)
|| provider.equals(LocationManager.FUSED_PROVIDER)) {
continue;
@@ -2664,16 +2756,16 @@
}
/**
- * Enable or disable location for a user
+ * Enable or disable location for a user
*
- * @param enabled true to enable location, false to disable location
- * @param userId the id of the user
+ * @param enabled true to enable location, false to disable location
+ * @param userId the id of the user
*/
@Override
public void setLocationEnabledForUser(boolean enabled, int userId) {
mContext.enforceCallingPermission(
- android.Manifest.permission.WRITE_SECURE_SETTINGS,
- "Requires WRITE_SECURE_SETTINGS permission");
+ android.Manifest.permission.WRITE_SECURE_SETTINGS,
+ "Requires WRITE_SECURE_SETTINGS permission");
// Check INTERACT_ACROSS_USERS permission if userId is not current user id.
checkInteractAcrossUsersPermission(userId);
@@ -2688,7 +2780,7 @@
allProvidersSet.addAll(allRealProviders);
// When disabling location, disable gps and network provider that could have been
// enabled by location mode api.
- if (enabled == false) {
+ if (!enabled) {
allProvidersSet.add(LocationManager.GPS_PROVIDER);
allProvidersSet.add(LocationManager.NETWORK_PROVIDER);
}
@@ -2723,26 +2815,34 @@
}
/**
- * Returns the current enabled/disabled status of a location provider and user
+ * Returns the current enabled/disabled status of a location provider and user
*
- * @param provider name of the provider
- * @param userId the id of the user
- * @return true if the provider exists and is enabled
+ * @param providerName name of the provider
+ * @param userId the id of the user
+ * @return true if the provider exists and is enabled
*/
@Override
- public boolean isProviderEnabledForUser(String provider, int userId) {
+ public boolean isProviderEnabledForUser(String providerName, int userId) {
// Check INTERACT_ACROSS_USERS permission if userId is not current user id.
checkInteractAcrossUsersPermission(userId);
+ if (!isLocationEnabledForUser(userId)) {
+ return false;
+ }
+
// Fused provider is accessed indirectly via criteria rather than the provider-based APIs,
// so we discourage its use
- if (LocationManager.FUSED_PROVIDER.equals(provider)) return false;
+ if (LocationManager.FUSED_PROVIDER.equals(providerName)) return false;
- int uid = Binder.getCallingUid();
- synchronized (mLock) {
- LocationProviderInterface p = mProvidersByName.get(provider);
- return p != null
- && isAllowedByUserSettingsLocked(provider, uid, userId);
+ long identity = Binder.clearCallingIdentity();
+ try {
+ LocationProvider provider;
+ synchronized (mLock) {
+ provider = mProvidersByName.get(providerName);
+ }
+ return provider != null && provider.isEnabled();
+ } finally {
+ Binder.restoreCallingIdentity(identity);
}
}
@@ -2750,66 +2850,13 @@
* Enable or disable a single location provider.
*
* @param provider name of the provider
- * @param enabled true to enable the provider. False to disable the provider
- * @param userId the id of the user to set
+ * @param enabled true to enable the provider. False to disable the provider
+ * @param userId the id of the user to set
* @return true if the value was set, false on errors
*/
@Override
public boolean setProviderEnabledForUser(String provider, boolean enabled, int userId) {
- mContext.enforceCallingPermission(
- android.Manifest.permission.WRITE_SECURE_SETTINGS,
- "Requires WRITE_SECURE_SETTINGS permission");
-
- // Check INTERACT_ACROSS_USERS permission if userId is not current user id.
- checkInteractAcrossUsersPermission(userId);
-
- // Fused provider is accessed indirectly via criteria rather than the provider-based APIs,
- // so we discourage its use
- if (LocationManager.FUSED_PROVIDER.equals(provider)) return false;
-
- long identity = Binder.clearCallingIdentity();
- try {
- synchronized (mLock) {
- // No such provider exists
- if (!mProvidersByName.containsKey(provider)) return false;
-
- // If it is a test provider, do not write to Settings.Secure
- if (mMockProviders.containsKey(provider)) {
- setTestProviderEnabled(provider, enabled);
- return true;
- }
-
- // to ensure thread safety, we write the provider name with a '+' or '-'
- // and let the SettingsProvider handle it rather than reading and modifying
- // the list of enabled providers.
- String providerChange = (enabled ? "+" : "-") + provider;
- return Settings.Secure.putStringForUser(
- mContext.getContentResolver(), Settings.Secure.LOCATION_PROVIDERS_ALLOWED,
- providerChange, userId);
- }
- } finally {
- Binder.restoreCallingIdentity(identity);
- }
- }
-
- /**
- * Read location provider status from Settings.Secure
- *
- * @param provider the location provider to query
- * @param userId the user id to query
- * @return true if the provider is enabled
- */
- private boolean isLocationProviderEnabledForUser(String provider, int userId) {
- long identity = Binder.clearCallingIdentity();
- try {
- // Use system settings
- ContentResolver cr = mContext.getContentResolver();
- String allowedProviders = Settings.Secure.getStringForUser(
- cr, Settings.Secure.LOCATION_PROVIDERS_ALLOWED, userId);
- return TextUtils.delimitedStringContains(allowedProviders, ',', provider);
- } finally {
- Binder.restoreCallingIdentity(identity);
- }
+ return false;
}
/**
@@ -2941,7 +2988,7 @@
long now = SystemClock.elapsedRealtime();
String provider = (passive ? LocationManager.PASSIVE_PROVIDER : location.getProvider());
// Skip if the provider is unknown.
- LocationProviderInterface p = mProvidersByName.get(provider);
+ LocationProvider p = mProvidersByName.get(provider);
if (p == null) return;
updateLastLocationLocked(location, provider);
// mLastLocation should have been updated from the updateLastLocationLocked call above.
@@ -3053,7 +3100,7 @@
LOCATION_DISABLE_STATUS_CALLBACKS, 1) == 0) {
long prevStatusUpdateTime = r.mLastStatusBroadcast;
if ((newStatusUpdateTime > prevStatusUpdateTime)
- && (prevStatusUpdateTime != 0 || status != LocationProvider.AVAILABLE)) {
+ && (prevStatusUpdateTime != 0 || status != AVAILABLE)) {
r.mLastStatusBroadcast = newStatusUpdateTime;
if (!receiver.callStatusChangedLocked(provider, status, extras)) {
@@ -3098,8 +3145,8 @@
/**
* Updates last location with the given location
*
- * @param location new location to update
- * @param provider Location provider to update for
+ * @param location new location to update
+ * @param provider Location provider to update for
*/
private void updateLastLocationLocked(Location location, String provider) {
Location noGPSLocation = location.getExtraLocation(Location.EXTRA_NO_GPS_LOCATION);
@@ -3154,13 +3201,11 @@
}
synchronized (mLock) {
- if (isAllowedByCurrentUserSettingsLocked(provider)) {
- if (!passive) {
- // notify passive provider of the new location
- mPassiveProvider.updateLocation(myLocation);
- }
- handleLocationChangedLocked(myLocation, passive);
+ if (!passive) {
+ // notify passive provider of the new location
+ mPassiveProvider.updateLocation(myLocation);
}
+ handleLocationChangedLocked(myLocation, passive);
}
}
@@ -3245,13 +3290,12 @@
if (LocationManager.GPS_PROVIDER.equals(name)
|| LocationManager.NETWORK_PROVIDER.equals(name)
|| LocationManager.FUSED_PROVIDER.equals(name)) {
- LocationProviderInterface p = mProvidersByName.get(name);
+ LocationProvider p = mProvidersByName.get(name);
if (p != null) {
removeProviderLocked(p);
}
}
addTestProviderLocked(name, properties);
- updateProvidersLocked();
}
Binder.restoreCallingIdentity(identity);
}
@@ -3260,9 +3304,12 @@
if (mProvidersByName.get(name) != null) {
throw new IllegalArgumentException("Provider \"" + name + "\" already exists");
}
- MockProvider provider = new MockProvider(name, this, properties);
+
+ LocationProvider provider = new LocationProvider(name);
+ MockProvider mockProvider = new MockProvider(provider, properties);
+
addProviderLocked(provider);
- mMockProviders.put(name, provider);
+ mMockProviders.put(name, mockProvider);
mLastLocation.put(name, null);
mLastLocationCoarseInterval.put(name, null);
}
@@ -3274,28 +3321,25 @@
}
synchronized (mLock) {
-
- // These methods can't be called after removing the test provider, so first make sure
- // we don't leave anything dangling.
- clearTestProviderEnabled(provider, opPackageName);
- clearTestProviderLocation(provider, opPackageName);
-
MockProvider mockProvider = mMockProviders.remove(provider);
if (mockProvider == null) {
throw new IllegalArgumentException("Provider \"" + provider + "\" unknown");
}
- long identity = Binder.clearCallingIdentity();
- removeProviderLocked(mProvidersByName.get(provider));
- // reinstate real provider if available
- LocationProviderInterface realProvider = mRealProviders.get(provider);
- if (realProvider != null) {
- addProviderLocked(realProvider);
+ long identity = Binder.clearCallingIdentity();
+ try {
+ removeProviderLocked(mProvidersByName.get(provider));
+
+ // reinstate real provider if available
+ LocationProvider realProvider = mRealProviders.get(provider);
+ if (realProvider != null) {
+ addProviderLocked(realProvider);
+ }
+ mLastLocation.put(provider, null);
+ mLastLocationCoarseInterval.put(provider, null);
+ } finally {
+ Binder.restoreCallingIdentity(identity);
}
- mLastLocation.put(provider, null);
- mLastLocationCoarseInterval.put(provider, null);
- updateProvidersLocked();
- Binder.restoreCallingIdentity(identity);
}
}
@@ -3325,23 +3369,11 @@
// clear calling identity so INSTALL_LOCATION_PROVIDER permission is not required
long identity = Binder.clearCallingIdentity();
- mockProvider.setLocation(mock);
- Binder.restoreCallingIdentity(identity);
- }
- }
-
- @Override
- public void clearTestProviderLocation(String provider, String opPackageName) {
- if (!canCallerAccessMockLocation(opPackageName)) {
- return;
- }
-
- synchronized (mLock) {
- MockProvider mockProvider = mMockProviders.get(provider);
- if (mockProvider == null) {
- throw new IllegalArgumentException("Provider \"" + provider + "\" unknown");
+ try {
+ mockProvider.setLocation(mock);
+ } finally {
+ Binder.restoreCallingIdentity(identity);
}
- mockProvider.clearLocation();
}
}
@@ -3350,36 +3382,6 @@
if (!canCallerAccessMockLocation(opPackageName)) {
return;
}
- setTestProviderEnabled(provider, enabled);
- }
-
- /** Enable or disable a test location provider. */
- private void setTestProviderEnabled(String provider, boolean enabled) {
- synchronized (mLock) {
- MockProvider mockProvider = mMockProviders.get(provider);
- if (mockProvider == null) {
- throw new IllegalArgumentException("Provider \"" + provider + "\" unknown");
- }
- long identity = Binder.clearCallingIdentity();
- if (enabled) {
- mockProvider.enable();
- mEnabledProviders.add(provider);
- mDisabledProviders.remove(provider);
- } else {
- mockProvider.disable();
- mEnabledProviders.remove(provider);
- mDisabledProviders.add(provider);
- }
- updateProvidersLocked();
- Binder.restoreCallingIdentity(identity);
- }
- }
-
- @Override
- public void clearTestProviderEnabled(String provider, String opPackageName) {
- if (!canCallerAccessMockLocation(opPackageName)) {
- return;
- }
synchronized (mLock) {
MockProvider mockProvider = mMockProviders.get(provider);
@@ -3387,10 +3389,11 @@
throw new IllegalArgumentException("Provider \"" + provider + "\" unknown");
}
long identity = Binder.clearCallingIdentity();
- mEnabledProviders.remove(provider);
- mDisabledProviders.remove(provider);
- updateProvidersLocked();
- Binder.restoreCallingIdentity(identity);
+ try {
+ mockProvider.setEnabled(enabled);
+ } finally {
+ Binder.restoreCallingIdentity(identity);
+ }
}
}
@@ -3450,10 +3453,11 @@
+ identity.mPackageName + ": " + isThrottlingExemptLocked(identity));
}
pw.println(" Overlay Provider Packages:");
- for (LocationProviderInterface provider : mProviders) {
- if (provider instanceof LocationProviderProxy) {
+ for (LocationProvider provider : mProviders) {
+ if (provider.mProvider instanceof LocationProviderProxy) {
pw.println(" " + provider.getName() + ": "
- + ((LocationProviderProxy) provider).getConnectedPackageName());
+ + ((LocationProviderProxy) provider.mProvider)
+ .getConnectedPackageName());
}
}
pw.println(" Historical Records by Provider:");
@@ -3479,25 +3483,12 @@
mGeofenceManager.dump(pw);
- if (mEnabledProviders.size() > 0) {
- pw.println(" Enabled Providers:");
- for (String i : mEnabledProviders) {
- pw.println(" " + i);
- }
-
- }
- if (mDisabledProviders.size() > 0) {
- pw.println(" Disabled Providers:");
- for (String i : mDisabledProviders) {
- pw.println(" " + i);
- }
- }
pw.append(" ");
mBlacklist.dump(pw);
if (mMockProviders.size() > 0) {
pw.println(" Mock Providers:");
for (Map.Entry<String, MockProvider> i : mMockProviders.entrySet()) {
- i.getValue().dump(pw, " ");
+ i.getValue().dump(fd, pw, args);
}
}
@@ -3514,13 +3505,7 @@
if (args.length > 0 && "short".equals(args[0])) {
return;
}
- for (LocationProviderInterface provider : mProviders) {
- pw.print(provider.getName() + " Internal State");
- if (provider instanceof LocationProviderProxy) {
- LocationProviderProxy proxy = (LocationProviderProxy) provider;
- pw.print(" (" + proxy.getConnectedPackageName() + ")");
- }
- pw.println(":");
+ for (LocationProvider provider : mProviders) {
provider.dump(fd, pw, args);
}
if (mGnssBatchingInProgress) {
diff --git a/services/core/java/com/android/server/ServiceWatcher.java b/services/core/java/com/android/server/ServiceWatcher.java
index 574f54a..d09823e 100644
--- a/services/core/java/com/android/server/ServiceWatcher.java
+++ b/services/core/java/com/android/server/ServiceWatcher.java
@@ -16,9 +16,7 @@
package com.android.server;
-import android.annotation.MainThread;
import android.annotation.Nullable;
-import android.annotation.WorkerThread;
import android.app.ActivityManager;
import android.content.BroadcastReceiver;
import android.content.ComponentName;
@@ -168,13 +166,13 @@
// called on handler thread
@GuardedBy("mBindLock")
protected void onBind() {
-
+ Preconditions.checkState(Looper.myLooper() == mHandler.getLooper());
}
// called on handler thread
@GuardedBy("mBindLock")
protected void onUnbind() {
-
+ Preconditions.checkState(Looper.myLooper() == mHandler.getLooper());
}
/**
@@ -205,12 +203,12 @@
@Override
public void onPackageRemoved(String packageName, int uid) {
- bindBestPackage(Objects.equals(packageName, getCurrentPackageName()));
+ bindBestPackage(Objects.equals(packageName, getCurrentPackageName()));
}
@Override
public boolean onPackageChanged(String packageName, int uid, String[] components) {
- bindBestPackage(Objects.equals(packageName, getCurrentPackageName()));
+ bindBestPackage(Objects.equals(packageName, getCurrentPackageName()));
return super.onPackageChanged(packageName, uid, components);
}
}.register(mContext, UserHandle.ALL, true, mHandler);
@@ -243,20 +241,16 @@
return true;
}
- /** Returns thje name of the currently connected package or null. */
+ /** Returns the name of the currently connected package or null. */
@Nullable
public String getCurrentPackageName() {
ComponentName bestComponent = mBestComponent;
return bestComponent == null ? null : bestComponent.getPackageName();
}
- public int getCurrentPackageVersion() {
- return mBestVersion;
- }
-
/**
- * Runs the given BinderRunner if currently connected. Returns true if it was run, and false
- * otherwise. All invocations to runOnBinder are run serially.
+ * Runs the given BinderRunner if currently connected. All invocations to runOnBinder are run
+ * serially.
*/
public final void runOnBinder(BinderRunner runner) {
synchronized (mBindLock) {
@@ -267,7 +261,7 @@
} catch (Exception e) {
// remote exceptions cannot be allowed to crash system server
Log.e(TAG, "exception while while running " + runner + " on " + service
- + " from " + mBestComponent.toShortString(), e);
+ + " from " + this, e);
}
}
}
@@ -280,14 +274,6 @@
UserHandle.USER_SYSTEM).isEmpty();
}
- /**
- * Searches and binds to the best package, or do nothing if the best package
- * is already bound, unless force rebinding is requested.
- *
- * @param forceRebind Force a rebinding to the best package if it's already
- * bound.
- */
- @WorkerThread
private void bindBestPackage(boolean forceRebind) {
Preconditions.checkState(Looper.myLooper() == mHandler.getLooper());
@@ -365,7 +351,6 @@
}
}
- @WorkerThread
private void bind(ComponentName component, int version, int userId) {
Preconditions.checkState(Looper.myLooper() == mHandler.getLooper());
@@ -382,7 +367,6 @@
UserHandle.of(userId));
}
- @WorkerThread
private void unbind() {
Preconditions.checkState(Looper.myLooper() == mHandler.getLooper());
@@ -396,7 +380,6 @@
mBestUserId = UserHandle.USER_NULL;
}
- @MainThread
@Override
public final void onServiceConnected(ComponentName component, IBinder binder) {
mHandler.post(() -> {
@@ -410,7 +393,6 @@
});
}
- @MainThread
@Override
public final void onServiceDisconnected(ComponentName component) {
mHandler.post(() -> {
diff --git a/services/core/java/com/android/server/TelephonyRegistry.java b/services/core/java/com/android/server/TelephonyRegistry.java
index a2cbfaa..b04ae17 100644
--- a/services/core/java/com/android/server/TelephonyRegistry.java
+++ b/services/core/java/com/android/server/TelephonyRegistry.java
@@ -67,7 +67,9 @@
import java.io.FileDescriptor;
import java.io.PrintWriter;
import java.util.ArrayList;
+import java.util.HashMap;
import java.util.List;
+import java.util.Map;
import java.util.NoSuchElementException;
/**
@@ -196,6 +198,8 @@
private ArrayList<List<PhysicalChannelConfig>> mPhysicalChannelConfigs;
+ private Map<Integer, List<EmergencyNumber>> mEmergencyNumberList;
+
private int[] mSrvccState;
private int mDefaultSubId = SubscriptionManager.INVALID_SUBSCRIPTION_ID;
@@ -229,8 +233,9 @@
| PhoneStateListener.LISTEN_CELL_INFO;
static final int ENFORCE_PHONE_STATE_PERMISSION_MASK =
- PhoneStateListener.LISTEN_CALL_FORWARDING_INDICATOR |
- PhoneStateListener.LISTEN_MESSAGE_WAITING_INDICATOR;
+ PhoneStateListener.LISTEN_CALL_FORWARDING_INDICATOR
+ | PhoneStateListener.LISTEN_MESSAGE_WAITING_INDICATOR
+ | PhoneStateListener.LISTEN_EMERGENCY_NUMBER_LIST;
static final int PRECISE_PHONE_STATE_PERMISSION_MASK =
PhoneStateListener.LISTEN_PRECISE_CALL_STATE |
@@ -357,6 +362,7 @@
mCellInfo = new ArrayList<List<CellInfo>>();
mSrvccState = new int[numPhones];
mPhysicalChannelConfigs = new ArrayList<List<PhysicalChannelConfig>>();
+ mEmergencyNumberList = new HashMap<>();
for (int i = 0; i < numPhones; i++) {
mCallState[i] = TelephonyManager.CALL_STATE_IDLE;
mDataActivity[i] = TelephonyManager.DATA_ACTIVITY_NONE;
@@ -752,6 +758,13 @@
remove(r.binder);
}
}
+ if ((events & PhoneStateListener.LISTEN_EMERGENCY_NUMBER_LIST) != 0) {
+ try {
+ r.callback.onEmergencyNumberListChanged(mEmergencyNumberList);
+ } catch (RemoteException ex) {
+ remove(r.binder);
+ }
+ }
if ((events & PhoneStateListener.LISTEN_PHONE_CAPABILITY_CHANGE) != 0) {
try {
r.callback.onPhoneCapabilityChanged(mPhoneCapability);
@@ -1665,10 +1678,30 @@
}
@Override
- public void notifyEmergencyNumberList(List<EmergencyNumber> emergencyNumberList) {
- // TODO checkPermission, modify Listener constent documentation
- // TODO implement multisim emergency number list update in listener
- // TODO implement PhoneStateListenerTest
+ public void notifyEmergencyNumberList() {
+ if (!checkNotifyPermission("notifyEmergencyNumberList()")) {
+ return;
+ }
+
+ synchronized (mRecords) {
+ mEmergencyNumberList = TelephonyManager.getDefault().getCurrentEmergencyNumberList();
+
+ for (Record r : mRecords) {
+ if (r.matchPhoneStateListenerEvent(
+ PhoneStateListener.LISTEN_EMERGENCY_NUMBER_LIST)) {
+ try {
+ r.callback.onEmergencyNumberListChanged(mEmergencyNumberList);
+ if (VDBG) {
+ log("notifyEmergencyNumberList: emergencyNumberList= "
+ + mEmergencyNumberList);
+ }
+ } catch (RemoteException ex) {
+ mRemoveList.add(r.binder);
+ }
+ }
+ }
+ handleRemoveListLocked();
+ }
}
@@ -1710,6 +1743,7 @@
pw.println("mPhoneCapability=" + mPhoneCapability);
pw.println("mPreferredDataSubId=" + mPreferredDataSubId);
pw.println("mRadioPowerState=" + mRadioPowerState);
+ pw.println("mEmergencyNumberList=" + mEmergencyNumberList);
pw.decreaseIndent();
diff --git a/services/core/java/com/android/server/am/ActiveServices.java b/services/core/java/com/android/server/am/ActiveServices.java
index 23287cf..f7acf7e 100644
--- a/services/core/java/com/android/server/am/ActiveServices.java
+++ b/services/core/java/com/android/server/am/ActiveServices.java
@@ -1205,10 +1205,20 @@
android.Manifest.permission.INSTANT_APP_FOREGROUND_SERVICE,
r.app.pid, r.appInfo.uid, "startForeground");
}
- } else if (r.appInfo.targetSdkVersion >= Build.VERSION_CODES.P) {
- mAm.enforcePermission(
- android.Manifest.permission.FOREGROUND_SERVICE,
- r.app.pid, r.appInfo.uid, "startForeground");
+ } else {
+ if (r.appInfo.targetSdkVersion >= Build.VERSION_CODES.P) {
+ mAm.enforcePermission(
+ android.Manifest.permission.FOREGROUND_SERVICE,
+ r.app.pid, r.appInfo.uid, "startForeground");
+ }
+ if (r.appInfo.targetSdkVersion >= Build.VERSION_CODES.Q) {
+ if (r.serviceInfo.getForegroundServiceType()
+ == ServiceInfo.FOREGROUND_SERVICE_TYPE_UNSPECIFIED) {
+ // STOPSHIP(b/120611119): replace log message with SecurityException.
+ Slog.w(TAG, "missing foregroundServiceType attribute in "
+ + "service element of manifest file");
+ }
+ }
}
boolean alreadyStartedOp = false;
boolean stopProcStatsOp = false;
diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java
index c16f1db..40da881 100644
--- a/services/core/java/com/android/server/am/ActivityManagerService.java
+++ b/services/core/java/com/android/server/am/ActivityManagerService.java
@@ -1199,8 +1199,8 @@
void setProfileProc(ProcessRecord profileProc) {
mProfileProc = profileProc;
if (mAtmInternal != null) {
- mAtmInternal.setProfileProc(
- profileProc.getWindowProcessController());
+ mAtmInternal.setProfileProc(profileProc == null ? null
+ : profileProc.getWindowProcessController());
}
}
diff --git a/services/core/java/com/android/server/am/CoreSettingsObserver.java b/services/core/java/com/android/server/am/CoreSettingsObserver.java
index 9cfd39c..65cd329 100644
--- a/services/core/java/com/android/server/am/CoreSettingsObserver.java
+++ b/services/core/java/com/android/server/am/CoreSettingsObserver.java
@@ -55,7 +55,12 @@
// add other system settings here...
sGlobalSettingToTypeMap.put(Settings.Global.DEBUG_VIEW_ATTRIBUTES, int.class);
- sGlobalSettingToTypeMap.put(Settings.Global.ANGLE_ENABLED_APP, String.class);
+ sGlobalSettingToTypeMap.put(
+ Settings.Global.GLOBAL_SETTINGS_ANGLE_GL_DRIVER_ALL_ANGLE, String.class);
+ sGlobalSettingToTypeMap.put(
+ Settings.Global.GLOBAL_SETTINGS_ANGLE_GL_DRIVER_SELECTION_PKGS, String.class);
+ sGlobalSettingToTypeMap.put(
+ Settings.Global.GLOBAL_SETTINGS_ANGLE_GL_DRIVER_SELECTION_VALUES, String.class);
sGlobalSettingToTypeMap.put(Settings.Global.ENABLE_GPU_DEBUG_LAYERS, int.class);
sGlobalSettingToTypeMap.put(Settings.Global.GPU_DEBUG_APP, String.class);
sGlobalSettingToTypeMap.put(Settings.Global.GPU_DEBUG_LAYERS, String.class);
diff --git a/services/core/java/com/android/server/display/DisplayTransformManager.java b/services/core/java/com/android/server/display/DisplayTransformManager.java
index 5ca1755..4ad26da 100644
--- a/services/core/java/com/android/server/display/DisplayTransformManager.java
+++ b/services/core/java/com/android/server/display/DisplayTransformManager.java
@@ -23,7 +23,6 @@
import android.os.RemoteException;
import android.os.ServiceManager;
import android.os.SystemProperties;
-import android.util.Log;
import android.util.Slog;
import android.util.SparseArray;
@@ -68,7 +67,7 @@
* SurfaceFlinger display color (managed, unmanaged, etc.).
*/
private static final int SURFACE_FLINGER_TRANSACTION_DISPLAY_COLOR = 1023;
- private static final int SURFACE_FLINGER_TRANSACTION_QUERY_WIDE_COLOR = 1030;
+ private static final int SURFACE_FLINGER_TRANSACTION_QUERY_COLOR_MANAGED = 1030;
private static final String PERSISTENT_PROPERTY_SATURATION = "persist.sys.sf.color_saturation";
private static final String PERSISTENT_PROPERTY_DISPLAY_COLOR = "persist.sys.sf.native_mode";
@@ -270,8 +269,8 @@
}
/**
- * Returns whether the screen is wide color gamut via SurfaceFlinger's
- * {@link #SURFACE_FLINGER_TRANSACTION_QUERY_WIDE_COLOR}.
+ * Returns whether the screen is color managed via SurfaceFlinger's
+ * {@link #SURFACE_FLINGER_TRANSACTION_QUERY_COLOR_MANAGED}.
*/
public boolean isDeviceColorManaged() {
final IBinder flinger = ServiceManager.getService(SURFACE_FLINGER);
@@ -280,10 +279,10 @@
final Parcel reply = Parcel.obtain();
data.writeInterfaceToken("android.ui.ISurfaceComposer");
try {
- flinger.transact(SURFACE_FLINGER_TRANSACTION_QUERY_WIDE_COLOR, data, reply, 0);
+ flinger.transact(SURFACE_FLINGER_TRANSACTION_QUERY_COLOR_MANAGED, data, reply, 0);
return reply.readBoolean();
} catch (RemoteException ex) {
- Log.e(TAG, "Failed to query wide color support", ex);
+ Slog.e(TAG, "Failed to query wide color support", ex);
} finally {
data.recycle();
reply.recycle();
@@ -305,7 +304,7 @@
try {
flinger.transact(SURFACE_FLINGER_TRANSACTION_SATURATION, data, null, 0);
} catch (RemoteException ex) {
- Log.e(TAG, "Failed to set saturation", ex);
+ Slog.e(TAG, "Failed to set saturation", ex);
} finally {
data.recycle();
}
@@ -325,7 +324,7 @@
try {
flinger.transact(SURFACE_FLINGER_TRANSACTION_DISPLAY_COLOR, data, null, 0);
} catch (RemoteException ex) {
- Log.e(TAG, "Failed to set display color", ex);
+ Slog.e(TAG, "Failed to set display color", ex);
} finally {
data.recycle();
}
@@ -336,7 +335,7 @@
try {
ActivityTaskManager.getService().updateConfiguration(null);
} catch (RemoteException e) {
- Log.e(TAG, "Could not update configuration", e);
+ Slog.e(TAG, "Could not update configuration", e);
}
}
}
diff --git a/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java b/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java
index a8da968..28a6ba4 100644
--- a/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java
+++ b/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java
@@ -984,9 +984,10 @@
// {@link #canShowInputMethodPickerLocked(IInputMethodClient)}.
mHandler.obtainMessage(
MSG_SHOW_IM_SUBTYPE_PICKER,
+ // TODO(b/120076400): Design and implement IME switcher for heterogeneous
+ // navbar configuration.
InputMethodManager.SHOW_IM_PICKER_MODE_INCLUDE_AUXILIARY_SUBTYPES,
- 0 /* arg2 */)
- .sendToTarget();
+ DEFAULT_DISPLAY).sendToTarget();
} else {
Slog.w(TAG, "Unexpected intent " + intent);
}
@@ -1617,7 +1618,8 @@
// Check whether or not this is a valid IPC. Assumes an IPC is valid when either
// 1) it comes from the system process
// 2) the calling process' user id is identical to the current user id IMMS thinks.
- private boolean calledFromValidUser() {
+ @GuardedBy("mMethodMap")
+ private boolean calledFromValidUserLocked() {
final int uid = Binder.getCallingUid();
final int userId = UserHandle.getUserId(uid);
if (DEBUG) {
@@ -1657,7 +1659,8 @@
* @param token The window token given to the input method when it was started.
* @return true if and only if non-null valid token is specified.
*/
- private boolean calledWithValidToken(@Nullable IBinder token) {
+ @GuardedBy("mMethodMap")
+ private boolean calledWithValidTokenLocked(@Nullable IBinder token) {
if (token == null && Binder.getCallingPid() == Process.myPid()) {
if (DEBUG) {
// TODO(b/34851776): Basically it's the caller's fault if we reach here.
@@ -1698,11 +1701,11 @@
}
private List<InputMethodInfo> getInputMethodList(final boolean isVrOnly) {
- // TODO: Make this work even for non-current users?
- if (!calledFromValidUser()) {
- return Collections.emptyList();
- }
synchronized (mMethodMap) {
+ // TODO: Make this work even for non-current users?
+ if (!calledFromValidUserLocked()) {
+ return Collections.emptyList();
+ }
ArrayList<InputMethodInfo> methodList = new ArrayList<>();
for (InputMethodInfo info : mMethodList) {
@@ -1716,11 +1719,11 @@
@Override
public List<InputMethodInfo> getEnabledInputMethodList() {
- // TODO: Make this work even for non-current users?
- if (!calledFromValidUser()) {
- return Collections.emptyList();
- }
synchronized (mMethodMap) {
+ // TODO: Make this work even for non-current users?
+ if (!calledFromValidUserLocked()) {
+ return Collections.emptyList();
+ }
return mSettings.getEnabledInputMethodListLocked();
}
}
@@ -1732,11 +1735,11 @@
@Override
public List<InputMethodSubtype> getEnabledInputMethodSubtypeList(String imiId,
boolean allowsImplicitlySelectedSubtypes) {
- // TODO: Make this work even for non-current users?
- if (!calledFromValidUser()) {
- return Collections.emptyList();
- }
synchronized (mMethodMap) {
+ // TODO: Make this work even for non-current users?
+ if (!calledFromValidUserLocked()) {
+ return Collections.emptyList();
+ }
final InputMethodInfo imi;
if (imiId == null && mCurMethodId != null) {
imi = mMethodMap.get(mCurMethodId);
@@ -2238,7 +2241,7 @@
private void updateStatusIcon(@NonNull IBinder token, String packageName,
@DrawableRes int iconId) {
synchronized (mMethodMap) {
- if (!calledWithValidToken(token)) {
+ if (!calledWithValidTokenLocked(token)) {
return;
}
final long ident = Binder.clearCallingIdentity();
@@ -2341,11 +2344,10 @@
@BinderThread
@SuppressWarnings("deprecation")
private void setImeWindowStatus(IBinder token, int vis, int backDisposition) {
- if (!calledWithValidToken(token)) {
- return;
- }
-
synchronized (mMethodMap) {
+ if (!calledWithValidTokenLocked(token)) {
+ return;
+ }
mImeWindowVis = vis;
mBackDisposition = backDisposition;
updateSystemUiLocked(token, vis, backDisposition);
@@ -2376,11 +2378,10 @@
@BinderThread
private void reportStartInput(IBinder token, IBinder startInputToken) {
- if (!calledWithValidToken(token)) {
- return;
- }
-
synchronized (mMethodMap) {
+ if (!calledWithValidTokenLocked(token)) {
+ return;
+ }
final IBinder targetWindow = mImeTargetWindowMap.get(startInputToken);
if (targetWindow != null && mLastImeTargetWindow != targetWindow) {
mWindowManagerInternal.updateInputMethodTargetWindow(token, targetWindow);
@@ -2391,7 +2392,7 @@
// Caution! This method is called in this class. Handle multi-user carefully
private void updateSystemUiLocked(IBinder token, int vis, int backDisposition) {
- if (!calledWithValidToken(token)) {
+ if (!calledWithValidTokenLocked(token)) {
return;
}
@@ -2450,10 +2451,10 @@
@Override
public void registerSuggestionSpansForNotification(SuggestionSpan[] spans) {
- if (!calledFromValidUser()) {
- return;
- }
synchronized (mMethodMap) {
+ if (!calledFromValidUserLocked()) {
+ return;
+ }
final InputMethodInfo currentImi = mMethodMap.get(mCurMethodId);
for (int i = 0; i < spans.length; ++i) {
SuggestionSpan ss = spans[i];
@@ -2466,10 +2467,10 @@
@Override
public boolean notifySuggestionPicked(SuggestionSpan span, String originalString, int index) {
- if (!calledFromValidUser()) {
- return false;
- }
synchronized (mMethodMap) {
+ if (!calledFromValidUserLocked()) {
+ return false;
+ }
final InputMethodInfo targetImi = mSecureSuggestionSpans.get(span);
// TODO: Do not send the intent if the process of the targetImi is already dead.
if (targetImi != null) {
@@ -2633,13 +2634,13 @@
@Override
public boolean showSoftInput(IInputMethodClient client, int flags,
ResultReceiver resultReceiver) {
- if (!calledFromValidUser()) {
- return false;
- }
int uid = Binder.getCallingUid();
- long ident = Binder.clearCallingIdentity();
- try {
- synchronized (mMethodMap) {
+ synchronized (mMethodMap) {
+ if (!calledFromValidUserLocked()) {
+ return false;
+ }
+ final long ident = Binder.clearCallingIdentity();
+ try {
if (mCurClient == null || client == null
|| mCurClient.client.asBinder() != client.asBinder()) {
// We need to check if this is the current client with
@@ -2657,9 +2658,9 @@
}
if (DEBUG) Slog.v(TAG, "Client requesting input be shown");
return showCurrentInputLocked(flags, resultReceiver);
+ } finally {
+ Binder.restoreCallingIdentity(ident);
}
- } finally {
- Binder.restoreCallingIdentity(ident);
}
}
@@ -2718,13 +2719,13 @@
@Override
public boolean hideSoftInput(IInputMethodClient client, int flags,
ResultReceiver resultReceiver) {
- if (!calledFromValidUser()) {
- return false;
- }
int uid = Binder.getCallingUid();
- long ident = Binder.clearCallingIdentity();
- try {
- synchronized (mMethodMap) {
+ synchronized (mMethodMap) {
+ if (!calledFromValidUserLocked()) {
+ return false;
+ }
+ final long ident = Binder.clearCallingIdentity();
+ try {
if (mCurClient == null || client == null
|| mCurClient.client.asBinder() != client.asBinder()) {
// We need to check if this is the current client with
@@ -2745,9 +2746,9 @@
if (DEBUG) Slog.v(TAG, "Client requesting input be hidden");
return hideCurrentInputLocked(flags, resultReceiver);
+ } finally {
+ Binder.restoreCallingIdentity(ident);
}
- } finally {
- Binder.restoreCallingIdentity(ident);
}
}
@@ -2827,14 +2828,14 @@
@SoftInputModeFlags int softInputMode, int windowFlags, EditorInfo attribute,
IInputContext inputContext, @MissingMethodFlags int missingMethods,
int unverifiedTargetSdkVersion) {
- // Needs to check the validity before clearing calling identity
- final boolean calledFromValidUser = calledFromValidUser();
InputBindResult res = null;
- long ident = Binder.clearCallingIdentity();
- try {
+ synchronized (mMethodMap) {
+ // Needs to check the validity before clearing calling identity
+ final boolean calledFromValidUser = calledFromValidUserLocked();
final int windowDisplayId =
mWindowManagerInternal.getDisplayIdForWindow(windowToken);
- synchronized (mMethodMap) {
+ final long ident = Binder.clearCallingIdentity();
+ try {
if (DEBUG) Slog.v(TAG, "startInputOrWindowGainedFocusInternal: reason="
+ InputMethodDebug.startInputReasonToString(startInputReason)
+ " client=" + client.asBinder()
@@ -3023,9 +3024,9 @@
res = InputBindResult.NULL_EDITOR_INFO;
}
}
+ } finally {
+ Binder.restoreCallingIdentity(ident);
}
- } finally {
- Binder.restoreCallingIdentity(ident);
}
return res;
@@ -3034,9 +3035,7 @@
private boolean canShowInputMethodPickerLocked(IInputMethodClient client) {
// TODO(yukawa): multi-display support.
final int uid = Binder.getCallingUid();
- if (UserHandle.getAppId(uid) == Process.SYSTEM_UID) {
- return true;
- } else if (mCurFocusedWindowClient != null && client != null
+ if (mCurFocusedWindowClient != null && client != null
&& mCurFocusedWindowClient.client.asBinder() == client.asBinder()) {
return true;
} else if (mCurIntent != null && InputMethodUtils.checkIfPackageBelongsToUid(
@@ -3044,22 +3043,17 @@
uid,
mCurIntent.getComponent().getPackageName())) {
return true;
- } else if (mContext.checkCallingPermission(
- android.Manifest.permission.WRITE_SECURE_SETTINGS)
- == PackageManager.PERMISSION_GRANTED) {
- return true;
}
-
return false;
}
@Override
public void showInputMethodPickerFromClient(
IInputMethodClient client, int auxiliarySubtypeMode) {
- if (!calledFromValidUser()) {
- return;
- }
synchronized (mMethodMap) {
+ if (!calledFromValidUserLocked()) {
+ return;
+ }
if(!canShowInputMethodPickerLocked(client)) {
Slog.w(TAG, "Ignoring showInputMethodPickerFromClient of uid "
+ Binder.getCallingUid() + ": " + client);
@@ -3068,11 +3062,26 @@
// Always call subtype picker, because subtype picker is a superset of input method
// picker.
- mHandler.sendMessage(mCaller.obtainMessageI(
- MSG_SHOW_IM_SUBTYPE_PICKER, auxiliarySubtypeMode));
+ mHandler.sendMessage(mCaller.obtainMessageII(
+ MSG_SHOW_IM_SUBTYPE_PICKER, auxiliarySubtypeMode,
+ (mCurClient != null) ? mCurClient.selfReportedDisplayId : DEFAULT_DISPLAY));
}
}
+ @Override
+ public void showInputMethodPickerFromSystem(IInputMethodClient client, int auxiliarySubtypeMode,
+ int displayId) {
+ if (mContext.checkCallingPermission(android.Manifest.permission.WRITE_SECURE_SETTINGS)
+ != PackageManager.PERMISSION_GRANTED) {
+ throw new SecurityException(
+ "showInputMethodPickerFromSystem requires WRITE_SECURE_SETTINGS permission");
+ }
+ // Always call subtype picker, because subtype picker is a superset of input method
+ // picker.
+ mHandler.sendMessage(mCaller.obtainMessageII(
+ MSG_SHOW_IM_SUBTYPE_PICKER, auxiliarySubtypeMode, displayId));
+ }
+
public boolean isInputMethodPickerShownForTest() {
synchronized(mMethodMap) {
if (mSwitchingDialog == null) {
@@ -3084,18 +3093,20 @@
@Override
public void setInputMethod(IBinder token, String id) {
- if (!calledFromValidUser()) {
- return;
+ synchronized (mMethodMap) {
+ if (!calledFromValidUserLocked()) {
+ return;
+ }
+ setInputMethodWithSubtypeIdLocked(token, id, NOT_A_SUBTYPE_ID);
}
- setInputMethodWithSubtypeId(token, id, NOT_A_SUBTYPE_ID);
}
@Override
public void setInputMethodAndSubtype(IBinder token, String id, InputMethodSubtype subtype) {
- if (!calledFromValidUser()) {
- return;
- }
synchronized (mMethodMap) {
+ if (!calledFromValidUserLocked()) {
+ return;
+ }
if (subtype != null) {
setInputMethodWithSubtypeIdLocked(token, id,
InputMethodUtils.getSubtypeIdFromHashCode(mMethodMap.get(id),
@@ -3109,22 +3120,22 @@
@Override
public void showInputMethodAndSubtypeEnablerFromClient(
IInputMethodClient client, String inputMethodId) {
- // TODO(yukawa): Should we verify the display ID?
- if (!calledFromValidUser()) {
- return;
- }
synchronized (mMethodMap) {
+ // TODO(yukawa): Should we verify the display ID?
+ if (!calledFromValidUserLocked()) {
+ return;
+ }
executeOrSendMessage(mCurMethod, mCaller.obtainMessageO(
MSG_SHOW_IM_SUBTYPE_ENABLER, inputMethodId));
}
}
- @Override
- public boolean switchToPreviousInputMethod(IBinder token) {
- if (!calledFromValidUser()) {
- return false;
- }
+ @BinderThread
+ private boolean switchToPreviousInputMethod(IBinder token) {
synchronized (mMethodMap) {
+ if (!calledWithValidTokenLocked(token)) {
+ return false;
+ }
final Pair<String, String> lastIme = mSettings.getLastInputMethodAndSubtypeLocked();
final InputMethodInfo lastImi;
if (lastIme != null) {
@@ -3191,13 +3202,10 @@
}
}
- @Override
- public boolean switchToNextInputMethod(IBinder token, boolean onlyCurrentIme) {
- if (!calledFromValidUser()) {
- return false;
- }
+ @BinderThread
+ private boolean switchToNextInputMethod(IBinder token, boolean onlyCurrentIme) {
synchronized (mMethodMap) {
- if (!calledWithValidToken(token)) {
+ if (!calledWithValidTokenLocked(token)) {
return false;
}
final ImeSubtypeListItem nextSubtype = mSwitchingController.getNextInputMethodLocked(
@@ -3213,11 +3221,8 @@
@BinderThread
private boolean shouldOfferSwitchingToNextInputMethod(@NonNull IBinder token) {
- if (!calledFromValidUser()) {
- return false;
- }
synchronized (mMethodMap) {
- if (!calledWithValidToken(token)) {
+ if (!calledWithValidTokenLocked(token)) {
return false;
}
final ImeSubtypeListItem nextSubtype = mSwitchingController.getNextInputMethodLocked(
@@ -3231,10 +3236,10 @@
@Override
public InputMethodSubtype getLastInputMethodSubtype() {
- if (!calledFromValidUser()) {
- return null;
- }
synchronized (mMethodMap) {
+ if (!calledFromValidUserLocked()) {
+ return null;
+ }
final Pair<String, String> lastIme = mSettings.getLastInputMethodAndSubtypeLocked();
// TODO: Handle the case of the last IME with no subtypes
if (lastIme == null || TextUtils.isEmpty(lastIme.first)
@@ -3257,13 +3262,13 @@
@Override
public void setAdditionalInputMethodSubtypes(String imiId, InputMethodSubtype[] subtypes) {
- if (!calledFromValidUser()) {
- return;
- }
// By this IPC call, only a process which shares the same uid with the IME can add
// additional input method subtypes to the IME.
if (TextUtils.isEmpty(imiId) || subtypes == null) return;
synchronized (mMethodMap) {
+ if (!calledFromValidUserLocked()) {
+ return;
+ }
if (!mSystemReady) {
return;
}
@@ -3329,12 +3334,6 @@
}
}
- private void setInputMethodWithSubtypeId(IBinder token, String id, int subtypeId) {
- synchronized (mMethodMap) {
- setInputMethodWithSubtypeIdLocked(token, id, subtypeId);
- }
- }
-
private void setInputMethodWithSubtypeIdLocked(IBinder token, String id, int subtypeId) {
if (token == null) {
if (mContext.checkCallingOrSelfPermission(
@@ -3360,11 +3359,8 @@
@BinderThread
private void hideMySoftInput(@NonNull IBinder token, int flags) {
- if (!calledFromValidUser()) {
- return;
- }
synchronized (mMethodMap) {
- if (!calledWithValidToken(token)) {
+ if (!calledWithValidTokenLocked(token)) {
return;
}
long ident = Binder.clearCallingIdentity();
@@ -3378,11 +3374,8 @@
@BinderThread
private void showMySoftInput(@NonNull IBinder token, int flags) {
- if (!calledFromValidUser()) {
- return;
- }
synchronized (mMethodMap) {
- if (!calledWithValidToken(token)) {
+ if (!calledWithValidTokenLocked(token)) {
return;
}
long ident = Binder.clearCallingIdentity();
@@ -3421,6 +3414,7 @@
switch (msg.what) {
case MSG_SHOW_IM_SUBTYPE_PICKER:
final boolean showAuxSubtypes;
+ final int displayId = msg.arg2;
switch (msg.arg1) {
case InputMethodManager.SHOW_IM_PICKER_MODE_AUTO:
// This is undocumented so far, but IMM#showInputMethodPicker() has been
@@ -3438,7 +3432,7 @@
Slog.e(TAG, "Unknown subtype picker mode = " + msg.arg1);
return false;
}
- showInputMethodMenu(showAuxSubtypes);
+ showInputMethodMenu(showAuxSubtypes, displayId);
return true;
case MSG_SHOW_IM_SUBTYPE_ENABLER:
@@ -3818,7 +3812,7 @@
&& mKeyguardManager.isKeyguardLocked() && mKeyguardManager.isKeyguardSecure();
}
- private void showInputMethodMenu(boolean showAuxSubtypes) {
+ private void showInputMethodMenu(boolean showAuxSubtypes, int displayId) {
if (DEBUG) Slog.v(TAG, "Show switching menu. showAuxSubtypes=" + showAuxSubtypes);
final boolean isScreenLocked = isScreenLocked();
@@ -3864,8 +3858,10 @@
}
}
+ final ActivityThread currentThread = ActivityThread.currentActivityThread();
final Context settingsContext = new ContextThemeWrapper(
- ActivityThread.currentActivityThread().getSystemUiContext(),
+ displayId == DEFAULT_DISPLAY ? currentThread.getSystemUiContext()
+ : currentThread.createSystemUiContext(displayId),
com.android.internal.R.style.Theme_DeviceDefault_Settings);
mDialogBuilder = new AlertDialog.Builder(settingsContext);
@@ -4195,11 +4191,11 @@
*/
@Override
public InputMethodSubtype getCurrentInputMethodSubtype() {
- // TODO: Make this work even for non-current users?
- if (!calledFromValidUser()) {
- return null;
- }
synchronized (mMethodMap) {
+ // TODO: Make this work even for non-current users?
+ if (!calledFromValidUserLocked()) {
+ return null;
+ }
return getCurrentInputMethodSubtypeLocked();
}
}
@@ -4274,11 +4270,11 @@
@Override
public boolean setCurrentInputMethodSubtype(InputMethodSubtype subtype) {
- // TODO: Make this work even for non-current users?
- if (!calledFromValidUser()) {
- return false;
- }
synchronized (mMethodMap) {
+ // TODO: Make this work even for non-current users?
+ if (!calledFromValidUserLocked()) {
+ return false;
+ }
if (subtype != null && mCurMethodId != null) {
InputMethodInfo imi = mMethodMap.get(mCurMethodId);
int subtypeId = InputMethodUtils.getSubtypeIdFromHashCode(imi, subtype.hashCode());
@@ -4532,10 +4528,6 @@
@BinderThread
private IInputContentUriToken createInputContentUriToken(@Nullable IBinder token,
@Nullable Uri contentUri, @Nullable String packageName) {
- if (!calledFromValidUser()) {
- return null;
- }
-
if (token == null) {
throw new NullPointerException("token");
}
@@ -4589,11 +4581,8 @@
@BinderThread
private void reportFullscreenMode(IBinder token, boolean fullscreen) {
- if (!calledFromValidUser()) {
- return;
- }
synchronized (mMethodMap) {
- if (!calledWithValidToken(token)) {
+ if (!calledWithValidTokenLocked(token)) {
return;
}
if (mCurClient != null && mCurClient.client != null) {
@@ -4933,11 +4922,6 @@
@RequiresPermission(Manifest.permission.WRITE_SECURE_SETTINGS)
private int handleShellCommandEnableDisableInputMethod(
@NonNull ShellCommand shellCommand, boolean enabled) {
- if (!calledFromValidUser()) {
- shellCommand.getErrPrintWriter().print(
- "Must be called from the foreground user or with INTERACT_ACROSS_USERS_FULL");
- return ShellCommandResult.FAILURE;
- }
final String id = shellCommand.getNextArgRequired();
final boolean previouslyEnabled;
@@ -4994,11 +4978,6 @@
@ShellCommandResult
@RequiresPermission(Manifest.permission.WRITE_SECURE_SETTINGS)
private int handleShellCommandResetInputMethod(@NonNull ShellCommand shellCommand) {
- if (!calledFromValidUser()) {
- shellCommand.getErrPrintWriter().print(
- "Must be called from the foreground user or with INTERACT_ACROSS_USERS_FULL");
- return ShellCommandResult.FAILURE;
- }
synchronized (mMethodMap) {
if (mContext.checkCallingOrSelfPermission(
android.Manifest.permission.WRITE_SECURE_SETTINGS)
diff --git a/services/core/java/com/android/server/inputmethod/MultiClientInputMethodManagerService.java b/services/core/java/com/android/server/inputmethod/MultiClientInputMethodManagerService.java
index 2b67fe7..5edb5c8 100644
--- a/services/core/java/com/android/server/inputmethod/MultiClientInputMethodManagerService.java
+++ b/services/core/java/com/android/server/inputmethod/MultiClientInputMethodManagerService.java
@@ -1541,6 +1541,13 @@
@BinderThread
@Override
+ public void showInputMethodPickerFromSystem(
+ IInputMethodClient client, int auxiliarySubtypeMode, int displayId) {
+ reportNotSupported();
+ }
+
+ @BinderThread
+ @Override
public void showInputMethodAndSubtypeEnablerFromClient(
IInputMethodClient client, String inputMethodId) {
reportNotSupported();
@@ -1595,20 +1602,6 @@
@BinderThread
@Override
- public boolean switchToPreviousInputMethod(IBinder token) {
- reportNotSupported();
- return false;
- }
-
- @BinderThread
- @Override
- public boolean switchToNextInputMethod(IBinder token, boolean onlyCurrentIme) {
- reportNotSupported();
- return false;
- }
-
- @BinderThread
- @Override
public void setAdditionalInputMethodSubtypes(String imiId, InputMethodSubtype[] subtypes) {
reportNotSupported();
}
diff --git a/services/core/java/com/android/server/job/JobSchedulerService.java b/services/core/java/com/android/server/job/JobSchedulerService.java
index 173f074..611c8b7 100644
--- a/services/core/java/com/android/server/job/JobSchedulerService.java
+++ b/services/core/java/com/android/server/job/JobSchedulerService.java
@@ -54,6 +54,8 @@
import android.os.BatteryStatsInternal;
import android.os.Binder;
import android.os.Handler;
+import android.os.IThermalService;
+import android.os.IThermalStatusListener;
import android.os.Looper;
import android.os.Message;
import android.os.Process;
@@ -62,6 +64,7 @@
import android.os.ServiceManager;
import android.os.ShellCallback;
import android.os.SystemClock;
+import android.os.Temperature;
import android.os.UserHandle;
import android.os.UserManagerInternal;
import android.provider.Settings;
@@ -75,6 +78,7 @@
import android.util.TimeUtils;
import android.util.proto.ProtoOutputStream;
+import com.android.internal.annotations.GuardedBy;
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.app.IBatteryStats;
import com.android.internal.util.ArrayUtils;
@@ -179,6 +183,11 @@
private final StorageController mStorageController;
/** Need directly for sending uid state changes */
private final DeviceIdleJobsController mDeviceIdleJobsController;
+ /** Need directly for receiving thermal events */
+ private IThermalService mThermalService;
+ /** Thermal constraint. */
+ @GuardedBy("mLock")
+ private boolean mThermalConstraint = false;
/**
* Queue of pending jobs. The JobServiceContext class will receive jobs from this list
@@ -310,6 +319,19 @@
}
/**
+ * Thermal event received from Thermal Service
+ */
+ private final class ThermalStatusListener extends IThermalStatusListener.Stub {
+ @Override public void onStatusChange(int status) {
+ // Throttle for Temperature.THROTTLING_SEVERE and above
+ synchronized (mLock) {
+ mThermalConstraint = status >= Temperature.THROTTLING_SEVERE;
+ }
+ onControllerStateChanged();
+ }
+ }
+
+ /**
* All times are in milliseconds. These constants are kept synchronized with the system
* global Settings. Any access to this class or its fields should be done while
* holding the JobSchedulerService.mLock lock.
@@ -1159,8 +1181,10 @@
// with just the foreground priority. This means that persistent processes
// can never be the top app priority... that is fine.
mUidPriorityOverride.put(uid, JobInfo.PRIORITY_TOP_APP);
+ } else if (procState <= ActivityManager.PROCESS_STATE_FOREGROUND_SERVICE) {
+ mUidPriorityOverride.put(uid, JobInfo.PRIORITY_FOREGROUND_SERVICE);
} else if (procState <= ActivityManager.PROCESS_STATE_BOUND_FOREGROUND_SERVICE) {
- mUidPriorityOverride.put(uid, JobInfo.PRIORITY_FOREGROUND_APP);
+ mUidPriorityOverride.put(uid, JobInfo.PRIORITY_BOUND_FOREGROUND_SERVICE);
} else {
mUidPriorityOverride.delete(uid);
}
@@ -1366,6 +1390,16 @@
}
// Remove any jobs that are not associated with any of the current users.
cancelJobsForNonExistentUsers();
+ // Register thermal callback
+ mThermalService = IThermalService.Stub.asInterface(
+ ServiceManager.getService(Context.THERMAL_SERVICE));
+ if (mThermalService != null) {
+ try {
+ mThermalService.registerThermalStatusListener(new ThermalStatusListener());
+ } catch (RemoteException e) {
+ Slog.e(TAG, "Failed to register thermal callback.", e);
+ }
+ }
} else if (phase == PHASE_THIRD_PARTY_APPS_CAN_START) {
synchronized (mLock) {
// Let's go!
@@ -1789,14 +1823,26 @@
}
}
+ private boolean isJobThermalConstrainedLocked(JobStatus job) {
+ return mThermalConstraint && job.hasConnectivityConstraint()
+ && (evaluateJobPriorityLocked(job) < JobInfo.PRIORITY_FOREGROUND_APP);
+ }
+
private void stopNonReadyActiveJobsLocked() {
for (int i=0; i<mActiveServices.size(); i++) {
JobServiceContext serviceContext = mActiveServices.get(i);
final JobStatus running = serviceContext.getRunningJobLocked();
- if (running != null && !running.isReady()) {
+ if (running == null) {
+ continue;
+ }
+ if (!running.isReady()) {
serviceContext.cancelExecutingJobLocked(
JobParameters.REASON_CONSTRAINTS_NOT_SATISFIED,
"cancelled due to unsatisfied constraints");
+ } else if (isJobThermalConstrainedLocked(running)) {
+ serviceContext.cancelExecutingJobLocked(
+ JobParameters.REASON_DEVICE_THERMAL,
+ "cancelled due to thermal condition");
}
}
}
@@ -2084,6 +2130,10 @@
return false;
}
+ if (isJobThermalConstrainedLocked(job)) {
+ return false;
+ }
+
final boolean jobPending = mPendingJobs.contains(job);
final boolean jobActive = isCurrentlyActiveLocked(job);
@@ -2196,7 +2246,7 @@
int evaluateJobPriorityLocked(JobStatus job) {
int priority = job.getPriority();
- if (priority >= JobInfo.PRIORITY_FOREGROUND_APP) {
+ if (priority >= JobInfo.PRIORITY_BOUND_FOREGROUND_SERVICE) {
return adjustJobPriority(priority, job);
}
int override = mUidPriorityOverride.get(job.getSourceUid(), 0);
@@ -3033,6 +3083,9 @@
pw.print(" In parole?: ");
pw.print(mInParole);
pw.println();
+ pw.print(" In thermal throttling?: ");
+ pw.print(mThermalConstraint);
+ pw.println();
pw.println();
pw.println("Started users: " + Arrays.toString(mStartedUsers));
@@ -3130,9 +3183,9 @@
pw.println(job.toShortString());
job.dump(pw, " ", false, nowElapsed);
int priority = evaluateJobPriorityLocked(job);
- if (priority != JobInfo.PRIORITY_DEFAULT) {
- pw.print(" Evaluated priority: "); pw.println(priority);
- }
+ pw.print(" Evaluated priority: ");
+ pw.println(JobInfo.getPriorityString(priority));
+
pw.print(" Tag: "); pw.println(job.getTag());
pw.print(" Enq: ");
TimeUtils.formatDuration(job.madePending - nowUptime, pw);
@@ -3163,9 +3216,9 @@
pw.println();
job.dump(pw, " ", false, nowElapsed);
int priority = evaluateJobPriorityLocked(jsc.getRunningJobLocked());
- if (priority != JobInfo.PRIORITY_DEFAULT) {
- pw.print(" Evaluated priority: "); pw.println(priority);
- }
+ pw.print(" Evaluated priority: ");
+ pw.println(JobInfo.getPriorityString(priority));
+
pw.print(" Active at ");
TimeUtils.formatDuration(job.madeActive - nowUptime, pw);
pw.print(", pending for ");
@@ -3208,6 +3261,7 @@
proto.write(JobSchedulerServiceDumpProto.NEXT_HEARTBEAT_TIME_MILLIS,
mLastHeartbeatTime + mConstants.STANDBY_HEARTBEAT_TIME - nowUptime);
proto.write(JobSchedulerServiceDumpProto.IN_PAROLE, mInParole);
+ proto.write(JobSchedulerServiceDumpProto.IN_THERMAL, mThermalConstraint);
for (int u : mStartedUsers) {
proto.write(JobSchedulerServiceDumpProto.STARTED_USERS, u);
@@ -3283,10 +3337,7 @@
job.writeToShortProto(proto, PendingJob.INFO);
job.dump(proto, PendingJob.DUMP, false, nowElapsed);
- int priority = evaluateJobPriorityLocked(job);
- if (priority != JobInfo.PRIORITY_DEFAULT) {
- proto.write(PendingJob.EVALUATED_PRIORITY, priority);
- }
+ proto.write(PendingJob.EVALUATED_PRIORITY, evaluateJobPriorityLocked(job));
proto.write(PendingJob.ENQUEUED_DURATION_MS, nowUptime - job.madePending);
proto.end(pjToken);
@@ -3318,10 +3369,8 @@
job.dump(proto, ActiveJob.RunningJob.DUMP, false, nowElapsed);
- int priority = evaluateJobPriorityLocked(jsc.getRunningJobLocked());
- if (priority != JobInfo.PRIORITY_DEFAULT) {
- proto.write(ActiveJob.RunningJob.EVALUATED_PRIORITY, priority);
- }
+ proto.write(ActiveJob.RunningJob.EVALUATED_PRIORITY,
+ evaluateJobPriorityLocked(jsc.getRunningJobLocked()));
proto.write(ActiveJob.RunningJob.TIME_SINCE_MADE_ACTIVE_MS,
nowUptime - job.madeActive);
diff --git a/services/core/java/com/android/server/job/controllers/JobStatus.java b/services/core/java/com/android/server/job/controllers/JobStatus.java
index 6deecbd..4341589 100644
--- a/services/core/java/com/android/server/job/controllers/JobStatus.java
+++ b/services/core/java/com/android/server/job/controllers/JobStatus.java
@@ -1321,7 +1321,8 @@
pw.print(prefix); pw.println(" PERSISTED");
}
if (job.getPriority() != 0) {
- pw.print(prefix); pw.print(" Priority: "); pw.println(job.getPriority());
+ pw.print(prefix); pw.print(" Priority: ");
+ pw.println(JobInfo.getPriorityString(job.getPriority()));
}
if (job.getFlags() != 0) {
pw.print(prefix); pw.print(" Flags: ");
diff --git a/services/core/java/com/android/server/location/AbstractLocationProvider.java b/services/core/java/com/android/server/location/AbstractLocationProvider.java
new file mode 100644
index 0000000..4c7c420
--- /dev/null
+++ b/services/core/java/com/android/server/location/AbstractLocationProvider.java
@@ -0,0 +1,149 @@
+/*
+ * Copyright (C) 2010 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.location;
+
+import android.location.Location;
+import android.location.LocationProvider;
+import android.os.Bundle;
+import android.os.WorkSource;
+
+import com.android.internal.location.ProviderProperties;
+import com.android.internal.location.ProviderRequest;
+
+import java.io.FileDescriptor;
+import java.io.PrintWriter;
+import java.util.List;
+
+/**
+ * Location Manager's interface for location providers.
+ *
+ * @hide
+ */
+public abstract class AbstractLocationProvider {
+
+ /**
+ * Interface for communicating from a location provider back to the location service.
+ */
+ public interface LocationProviderManager {
+
+ /**
+ * Called on location provider construction to make the location service aware of this
+ * provider and what it's initial enabled/disabled state should be.
+ */
+ void onAttachProvider(AbstractLocationProvider locationProvider, boolean initiallyEnabled);
+
+ /**
+ * May be called to inform the location service of a change in this location provider's
+ * enabled/disabled state.
+ */
+ void onSetEnabled(boolean enabled);
+
+ /**
+ * May be called to inform the location service of a change in this location provider's
+ * properties.
+ */
+ void onSetProperties(ProviderProperties properties);
+
+ /**
+ * May be called to inform the location service that this provider has a new location
+ * available.
+ */
+ void onReportLocation(Location location);
+
+ /**
+ * May be called to inform the location service that this provider has a new location
+ * available.
+ */
+ void onReportLocation(List<Location> locations);
+ }
+
+ private final LocationProviderManager mLocationProviderManager;
+
+ protected AbstractLocationProvider(LocationProviderManager locationProviderManager) {
+ this(locationProviderManager, true);
+ }
+
+ protected AbstractLocationProvider(LocationProviderManager locationProviderManager,
+ boolean initiallyEnabled) {
+ mLocationProviderManager = locationProviderManager;
+ mLocationProviderManager.onAttachProvider(this, initiallyEnabled);
+ }
+
+ /**
+ * Call this method to report a new location. May be called from any thread.
+ */
+ protected void reportLocation(Location location) {
+ mLocationProviderManager.onReportLocation(location);
+ }
+
+ /**
+ * Call this method to report a new location. May be called from any thread.
+ */
+ protected void reportLocation(List<Location> locations) {
+ mLocationProviderManager.onReportLocation(locations);
+ }
+
+ /**
+ * Call this method to report a change in provider enabled/disabled status. May be called from
+ * any thread.
+ */
+ protected void setEnabled(boolean enabled) {
+ mLocationProviderManager.onSetEnabled(enabled);
+ }
+
+ /**
+ * Call this method to report a change in provider properties. May be called from
+ * any thread.
+ */
+ protected void setProperties(ProviderProperties properties) {
+ mLocationProviderManager.onSetProperties(properties);
+ }
+
+ /**
+ * Called when the location service delivers a new request for fulfillment to the provider.
+ * Replaces any previous requests completely.
+ */
+ public abstract void setRequest(ProviderRequest request, WorkSource source);
+
+ /**
+ * Called to dump debug or log information.
+ */
+ public abstract void dump(FileDescriptor fd, PrintWriter pw, String[] args);
+
+ /**
+ * Retrieves the current status of the provider.
+ *
+ * @deprecated Will be removed in a future release.
+ */
+ @Deprecated
+ public int getStatus(Bundle extras) {
+ return LocationProvider.AVAILABLE;
+ }
+
+ /**
+ * Retrieves the last update time of the status of the provider.
+ *
+ * @deprecated Will be removed in a future release.
+ */
+ @Deprecated
+ public long getStatusUpdateTime() {
+ return 0;
+ }
+
+ /** Sends a custom command to this provider. */
+ public abstract void sendExtraCommand(String command, Bundle extras);
+}
diff --git a/services/core/java/com/android/server/location/GnssGeofenceProvider.java b/services/core/java/com/android/server/location/GnssGeofenceProvider.java
index 6ac4aeb..a84b0b1 100644
--- a/services/core/java/com/android/server/location/GnssGeofenceProvider.java
+++ b/services/core/java/com/android/server/location/GnssGeofenceProvider.java
@@ -1,18 +1,12 @@
package com.android.server.location;
import android.location.IGpsGeofenceHardware;
-import android.os.Handler;
-import android.os.IBinder;
-import android.os.Looper;
import android.util.Log;
import android.util.SparseArray;
+import com.android.internal.annotations.GuardedBy;
import com.android.internal.annotations.VisibleForTesting;
-import java.util.concurrent.Callable;
-import java.util.concurrent.ExecutionException;
-import java.util.concurrent.FutureTask;
-
/**
* Manages GNSS Geofence operations.
*/
@@ -34,26 +28,26 @@
public boolean paused;
}
+ private final Object mLock = new Object();
+ @GuardedBy("mLock")
private final GnssGeofenceProviderNative mNative;
+ @GuardedBy("mLock")
private final SparseArray<GeofenceEntry> mGeofenceEntries = new SparseArray<>();
- private final Handler mHandler;
- GnssGeofenceProvider(Looper looper) {
- this(looper, new GnssGeofenceProviderNative());
+ GnssGeofenceProvider() {
+ this(new GnssGeofenceProviderNative());
}
@VisibleForTesting
- GnssGeofenceProvider(Looper looper, GnssGeofenceProviderNative gnssGeofenceProviderNative) {
- mHandler = new Handler(looper);
+ GnssGeofenceProvider(GnssGeofenceProviderNative gnssGeofenceProviderNative) {
mNative = gnssGeofenceProviderNative;
}
- // TODO(b/37460011): use this method in HAL death recovery.
void resumeIfStarted() {
if (DEBUG) {
Log.d(TAG, "resumeIfStarted");
}
- mHandler.post(() -> {
+ synchronized (mLock) {
for (int i = 0; i < mGeofenceEntries.size(); i++) {
GeofenceEntry entry = mGeofenceEntries.valueAt(i);
boolean added = mNative.addGeofence(entry.geofenceId, entry.latitude,
@@ -65,30 +59,21 @@
mNative.pauseGeofence(entry.geofenceId);
}
}
- });
- }
-
- private boolean runOnHandlerThread(Callable<Boolean> callable) {
- FutureTask<Boolean> futureTask = new FutureTask<>(callable);
- mHandler.post(futureTask);
- try {
- return futureTask.get();
- } catch (InterruptedException | ExecutionException e) {
- Log.e(TAG, "Failed running callable.", e);
}
- return false;
}
@Override
public boolean isHardwareGeofenceSupported() {
- return runOnHandlerThread(mNative::isGeofenceSupported);
+ synchronized (mLock) {
+ return mNative.isGeofenceSupported();
+ }
}
@Override
public boolean addCircularHardwareGeofence(int geofenceId, double latitude,
double longitude, double radius, int lastTransition, int monitorTransitions,
int notificationResponsiveness, int unknownTimer) {
- return runOnHandlerThread(() -> {
+ synchronized (mLock) {
boolean added = mNative.addGeofence(geofenceId, latitude, longitude, radius,
lastTransition, monitorTransitions, notificationResponsiveness,
unknownTimer);
@@ -105,23 +90,23 @@
mGeofenceEntries.put(geofenceId, entry);
}
return added;
- });
+ }
}
@Override
public boolean removeHardwareGeofence(int geofenceId) {
- return runOnHandlerThread(() -> {
+ synchronized (mLock) {
boolean removed = mNative.removeGeofence(geofenceId);
if (removed) {
mGeofenceEntries.remove(geofenceId);
}
return removed;
- });
+ }
}
@Override
public boolean pauseHardwareGeofence(int geofenceId) {
- return runOnHandlerThread(() -> {
+ synchronized (mLock) {
boolean paused = mNative.pauseGeofence(geofenceId);
if (paused) {
GeofenceEntry entry = mGeofenceEntries.get(geofenceId);
@@ -130,12 +115,12 @@
}
}
return paused;
- });
+ }
}
@Override
public boolean resumeHardwareGeofence(int geofenceId, int monitorTransitions) {
- return runOnHandlerThread(() -> {
+ synchronized (mLock) {
boolean resumed = mNative.resumeGeofence(geofenceId, monitorTransitions);
if (resumed) {
GeofenceEntry entry = mGeofenceEntries.get(geofenceId);
@@ -145,7 +130,7 @@
}
}
return resumed;
- });
+ }
}
@VisibleForTesting
diff --git a/services/core/java/com/android/server/location/GnssLocationProvider.java b/services/core/java/com/android/server/location/GnssLocationProvider.java
index d5e4681..29e1878 100644
--- a/services/core/java/com/android/server/location/GnssLocationProvider.java
+++ b/services/core/java/com/android/server/location/GnssLocationProvider.java
@@ -31,10 +31,7 @@
import android.location.GnssMeasurementsEvent;
import android.location.GnssNavigationMessage;
import android.location.GnssStatus;
-import android.location.IGnssStatusListener;
-import android.location.IGnssStatusProvider;
import android.location.IGpsGeofenceHardware;
-import android.location.ILocationManager;
import android.location.INetInitiatedListener;
import android.location.Location;
import android.location.LocationListener;
@@ -84,6 +81,10 @@
import java.io.FileInputStream;
import java.io.IOException;
import java.io.PrintWriter;
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
@@ -97,8 +98,18 @@
*
* {@hide}
*/
-public class GnssLocationProvider extends LocationProviderInterface
- implements InjectNtpTimeCallback, GnssSatelliteBlacklistCallback {
+public class GnssLocationProvider extends AbstractLocationProvider implements
+ InjectNtpTimeCallback,
+ GnssSatelliteBlacklistCallback {
+
+ /**
+ * Indicates that this method is a native entry point. Useful purely for IDEs which can
+ * understand entry points, and thus eliminate incorrect warnings about methods not used.
+ */
+ @Target(ElementType.METHOD)
+ @Retention(RetentionPolicy.SOURCE)
+ private @interface NativeEntryPoint {
+ }
private static final String TAG = "GnssLocationProvider";
@@ -249,7 +260,7 @@
}
public void set(int svCount, int meanCn0, int maxCn0) {
- synchronized(this) {
+ synchronized (this) {
mSvCount = svCount;
mMeanCn0 = meanCn0;
mMaxCn0 = maxCn0;
@@ -258,7 +269,7 @@
}
public void reset() {
- set(0,0,0);
+ set(0, 0, 0);
}
// Also used by outside methods to add to other bundles
@@ -314,7 +325,7 @@
MAX_RETRY_INTERVAL);
// true if we are enabled, protected by this
- private boolean mEnabled;
+ private boolean mEnabled = true;
// states for injecting ntp and downloading xtra data
private static final int STATE_PENDING_NETWORK = 0;
@@ -328,9 +339,6 @@
// true if GPS is navigating
private boolean mNavigating;
- // true if GPS engine is on
- private boolean mEngineOn;
-
// requested frequency of fixes, in milliseconds
private int mFixInterval = 1000;
@@ -380,9 +388,8 @@
private boolean mSuplEsEnabled = false;
private final Context mContext;
- private final ILocationManager mILocationManager;
private final LocationExtras mLocationExtras = new LocationExtras();
- private final GnssStatusListenerHelper mListenerHelper;
+ private final GnssStatusListenerHelper mGnssStatusListenerHelper;
private final GnssSatelliteBlacklistHelper mGnssSatelliteBlacklistHelper;
private final GnssMeasurementsProvider mGnssMeasurementsProvider;
private final GnssNavigationMessageProvider mGnssNavigationMessageProvider;
@@ -443,20 +450,8 @@
// GNSS Metrics
private GnssMetrics mGnssMetrics;
- private final IGnssStatusProvider mGnssStatusProvider = new IGnssStatusProvider.Stub() {
- @Override
- public void registerGnssStatusCallback(IGnssStatusListener callback) {
- mListenerHelper.addListener(callback);
- }
-
- @Override
- public void unregisterGnssStatusCallback(IGnssStatusListener callback) {
- mListenerHelper.removeListener(callback);
- }
- };
-
- public IGnssStatusProvider getGnssStatusProvider() {
- return mGnssStatusProvider;
+ public GnssStatusListenerHelper getGnssStatusProvider() {
+ return mGnssStatusListenerHelper;
}
public IGpsGeofenceHardware getGpsGeofenceProxy() {
@@ -479,17 +474,22 @@
return;
}
- if (action.equals(ALARM_WAKEUP)) {
- startNavigating(false);
- } else if (action.equals(ALARM_TIMEOUT)) {
- hibernate();
- } else if (PowerManager.ACTION_POWER_SAVE_MODE_CHANGED.equals(action)
- || PowerManager.ACTION_DEVICE_IDLE_MODE_CHANGED.equals(action)
- || Intent.ACTION_SCREEN_OFF.equals(action)
- || Intent.ACTION_SCREEN_ON.equals(action)) {
- updateLowPowerMode();
- } else if (action.equals(SIM_STATE_CHANGED)) {
- subscriptionOrSimChanged(context);
+ switch (action) {
+ case ALARM_WAKEUP:
+ startNavigating(false);
+ break;
+ case ALARM_TIMEOUT:
+ hibernate();
+ break;
+ case PowerManager.ACTION_POWER_SAVE_MODE_CHANGED:
+ case PowerManager.ACTION_DEVICE_IDLE_MODE_CHANGED:
+ case Intent.ACTION_SCREEN_OFF:
+ case Intent.ACTION_SCREEN_ON:
+ updateLowPowerMode();
+ break;
+ case SIM_STATE_CHANGED:
+ subscriptionOrSimChanged(context);
+ break;
}
}
};
@@ -507,9 +507,7 @@
*/
@Override
public void onUpdateSatelliteBlacklist(int[] constellations, int[] svids) {
- mHandler.post(()->{
- native_set_satellite_blacklist(constellations, svids);
- });
+ mHandler.post(() -> native_set_satellite_blacklist(constellations, svids));
}
private void subscriptionOrSimChanged(Context context) {
@@ -572,7 +570,7 @@
}
interface SetCarrierProperty {
- public boolean set(int value);
+ boolean set(int value);
}
private void reloadGpsProperties(Context context, Properties properties) {
@@ -587,7 +585,7 @@
/*
* Overlay carrier properties from a debug configuration file.
*/
- loadPropertiesFromFile(DEBUG_PROPERTIES_FILE, properties);
+ loadPropertiesFromFile(properties);
// TODO: we should get rid of C2K specific setting.
setSuplHostPort(properties.getProperty("SUPL_HOST"),
properties.getProperty("SUPL_PORT"));
@@ -603,15 +601,15 @@
if (native_is_gnss_configuration_supported()) {
Map<String, SetCarrierProperty> map = new HashMap<String, SetCarrierProperty>() {
{
- put("SUPL_VER", (val) -> native_set_supl_version(val));
- put("SUPL_MODE", (val) -> native_set_supl_mode(val));
- put("SUPL_ES", (val) -> native_set_supl_es(val));
- put("LPP_PROFILE", (val) -> native_set_lpp_profile(val));
+ put("SUPL_VER", GnssLocationProvider::native_set_supl_version);
+ put("SUPL_MODE", GnssLocationProvider::native_set_supl_mode);
+ put("SUPL_ES", GnssLocationProvider::native_set_supl_es);
+ put("LPP_PROFILE", GnssLocationProvider::native_set_lpp_profile);
put("A_GLONASS_POS_PROTOCOL_SELECT",
- (val) -> native_set_gnss_pos_protocol_select(val));
+ GnssLocationProvider::native_set_gnss_pos_protocol_select);
put("USE_EMERGENCY_PDN_FOR_EMERGENCY_SUPL",
- (val) -> native_set_emergency_supl_pdn(val));
- put("GPS_LOCK", (val) -> native_set_gps_lock(val));
+ GnssLocationProvider::native_set_emergency_supl_pdn);
+ put("GPS_LOCK", GnssLocationProvider::native_set_gps_lock);
}
};
@@ -622,7 +620,7 @@
try {
int propertyValueInt = Integer.decode(propertyValueString);
boolean result = entry.getValue().set(propertyValueInt);
- if (result == false) {
+ if (!result) {
Log.e(TAG, "Unable to set " + propertyName);
}
} catch (NumberFormatException e) {
@@ -664,10 +662,9 @@
}
}
- private boolean loadPropertiesFromFile(String filename,
- Properties properties) {
+ private void loadPropertiesFromFile(Properties properties) {
try {
- File file = new File(filename);
+ File file = new File(DEBUG_PROPERTIES_FILE);
FileInputStream stream = null;
try {
stream = new FileInputStream(file);
@@ -677,16 +674,15 @@
}
} catch (IOException e) {
- if (DEBUG) Log.d(TAG, "Could not open GPS configuration file " + filename);
- return false;
+ if (DEBUG) Log.d(TAG, "Could not open GPS configuration file " + DEBUG_PROPERTIES_FILE);
}
- return true;
}
- public GnssLocationProvider(Context context, ILocationManager ilocationManager,
+ public GnssLocationProvider(Context context, LocationProviderManager locationProviderManager,
Looper looper) {
+ super(locationProviderManager, true);
+
mContext = context;
- mILocationManager = ilocationManager;
// Create a wake lock
mPowerManager = (PowerManager) mContext.getSystemService(Context.POWER_SERVICE);
@@ -730,7 +726,7 @@
mNetInitiatedListener,
mSuplEsEnabled);
- mListenerHelper = new GnssStatusListenerHelper(mHandler) {
+ mGnssStatusListenerHelper = new GnssStatusListenerHelper(mContext, mHandler) {
@Override
protected boolean isAvailableInPlatform() {
return isSupported();
@@ -749,7 +745,7 @@
}
};
- mGnssNavigationMessageProvider = new GnssNavigationMessageProvider(mHandler) {
+ mGnssNavigationMessageProvider = new GnssNavigationMessageProvider(mContext, mHandler) {
@Override
protected boolean isGpsEnabled() {
return isEnabled();
@@ -762,20 +758,21 @@
looper, this);
mHandler.post(mGnssSatelliteBlacklistHelper::updateSatelliteBlacklist);
mGnssBatchingProvider = new GnssBatchingProvider();
- mGnssGeofenceProvider = new GnssGeofenceProvider(looper);
- }
+ mGnssGeofenceProvider = new GnssGeofenceProvider();
- /**
- * Returns the name of this provider.
- */
- @Override
- public String getName() {
- return LocationManager.GPS_PROVIDER;
- }
+ IntentFilter intentFilter = new IntentFilter();
+ intentFilter.addAction(Intent.ACTION_SHUTDOWN);
+ mContext.registerReceiverAsUser(new BroadcastReceiver() {
+ @Override
+ public void onReceive(Context context, Intent intent) {
+ if (getSendingUserId() == UserHandle.USER_ALL) {
+ mEnabled = false;
+ handleDisable();
+ }
+ }
+ }, UserHandle.ALL, intentFilter, null, mHandler);
- @Override
- public ProviderProperties getProperties() {
- return PROPERTIES;
+ setProperties(PROPERTIES);
}
/**
@@ -840,9 +837,9 @@
locationManager.requestLocationUpdates(provider,
LOCATION_UPDATE_MIN_TIME_INTERVAL_MILLIS, /*minDistance=*/ 0,
locationListener, mHandler.getLooper());
- locationListener.numLocationUpdateRequest++;
+ locationListener.mNumLocationUpdateRequest++;
mHandler.postDelayed(() -> {
- if (--locationListener.numLocationUpdateRequest == 0) {
+ if (--locationListener.mNumLocationUpdateRequest == 0) {
Log.i(TAG,
String.format("Removing location updates from %s provider.", provider));
locationManager.removeUpdates(locationListener);
@@ -905,43 +902,40 @@
// hold wake lock while task runs
mDownloadXtraWakeLock.acquire(DOWNLOAD_XTRA_DATA_TIMEOUT_MS);
Log.i(TAG, "WakeLock acquired by handleDownloadXtraData()");
- AsyncTask.THREAD_POOL_EXECUTOR.execute(new Runnable() {
- @Override
- public void run() {
- GpsXtraDownloader xtraDownloader = new GpsXtraDownloader(mProperties);
- byte[] data = xtraDownloader.downloadXtraData();
- if (data != null) {
- if (DEBUG) Log.d(TAG, "calling native_inject_xtra_data");
- native_inject_xtra_data(data, data.length);
- mXtraBackOff.reset();
- }
+ AsyncTask.THREAD_POOL_EXECUTOR.execute(() -> {
+ GpsXtraDownloader xtraDownloader = new GpsXtraDownloader(mProperties);
+ byte[] data = xtraDownloader.downloadXtraData();
+ if (data != null) {
+ if (DEBUG) Log.d(TAG, "calling native_inject_xtra_data");
+ native_inject_xtra_data(data, data.length);
+ mXtraBackOff.reset();
+ }
- sendMessage(DOWNLOAD_XTRA_DATA_FINISHED, 0, null);
+ sendMessage(DOWNLOAD_XTRA_DATA_FINISHED, 0, null);
- if (data == null) {
- // try again later
- // since this is delayed and not urgent we do not hold a wake lock here
- mHandler.sendEmptyMessageDelayed(DOWNLOAD_XTRA_DATA,
- mXtraBackOff.nextBackoffMillis());
- }
+ if (data == null) {
+ // try again later
+ // since this is delayed and not urgent we do not hold a wake lock here
+ mHandler.sendEmptyMessageDelayed(DOWNLOAD_XTRA_DATA,
+ mXtraBackOff.nextBackoffMillis());
+ }
- // Release wake lock held by task, synchronize on mLock in case multiple
- // download tasks overrun.
- synchronized (mLock) {
- if (mDownloadXtraWakeLock.isHeld()) {
- // This wakelock may have time-out, if a timeout was specified.
- // Catch (and ignore) any timeout exceptions.
- try {
- mDownloadXtraWakeLock.release();
- if (DEBUG) Log.d(TAG, "WakeLock released by handleDownloadXtraData()");
- } catch (Exception e) {
- Log.i(TAG, "Wakelock timeout & release race exception in "
- + "handleDownloadXtraData()", e);
- }
- } else {
- Log.e(TAG, "WakeLock expired before release in "
- + "handleDownloadXtraData()");
+ // Release wake lock held by task, synchronize on mLock in case multiple
+ // download tasks overrun.
+ synchronized (mLock) {
+ if (mDownloadXtraWakeLock.isHeld()) {
+ // This wakelock may have time-out, if a timeout was specified.
+ // Catch (and ignore) any timeout exceptions.
+ try {
+ mDownloadXtraWakeLock.release();
+ if (DEBUG) Log.d(TAG, "WakeLock released by handleDownloadXtraData()");
+ } catch (Exception e) {
+ Log.i(TAG, "Wakelock timeout & release race exception in "
+ + "handleDownloadXtraData()", e);
}
+ } else {
+ Log.e(TAG, "WakeLock expired before release in "
+ + "handleDownloadXtraData()");
}
}
});
@@ -954,21 +948,6 @@
}
}
- /**
- * Enables this provider. When enabled, calls to getStatus()
- * must be handled. Hardware may be started up
- * when the provider is enabled.
- */
- @Override
- public void enable() {
- synchronized (mLock) {
- if (mEnabled) return;
- mEnabled = true;
- }
-
- sendMessage(ENABLE, 1, null);
- }
-
private void setSuplHostPort(String hostString, String portString) {
if (hostString != null) {
mSuplServerHost = hostString;
@@ -1052,21 +1031,6 @@
}
}
- /**
- * Disables this provider. When disabled, calls to getStatus()
- * need not be handled. Hardware may be shut
- * down while the provider is disabled.
- */
- @Override
- public void disable() {
- synchronized (mLock) {
- if (!mEnabled) return;
- mEnabled = false;
- }
-
- sendMessage(ENABLE, 0, null);
- }
-
private void handleDisable() {
if (DEBUG) Log.d(TAG, "handleDisable");
@@ -1083,7 +1047,6 @@
mGnssNavigationMessageProvider.onGpsEnabledChanged();
}
- @Override
public boolean isEnabled() {
synchronized (mLock) {
return mEnabled;
@@ -1147,7 +1110,7 @@
updateClientUids(mWorkSource);
mFixInterval = (int) mProviderRequest.interval;
- mLowPowerMode = (boolean) mProviderRequest.lowPowerMode;
+ mLowPowerMode = mProviderRequest.lowPowerMode;
// check for overflow
if (mFixInterval != mProviderRequest.interval) {
Log.w(TAG, "interval overflow: " + mProviderRequest.interval);
@@ -1171,7 +1134,8 @@
// set timer to give up if we do not receive a fix within NO_FIX_TIMEOUT
// and our fix interval is not short
mAlarmManager.set(AlarmManager.ELAPSED_REALTIME_WAKEUP,
- SystemClock.elapsedRealtime() + NO_FIX_TIMEOUT, mTimeoutIntent); }
+ SystemClock.elapsedRealtime() + NO_FIX_TIMEOUT, mTimeoutIntent);
+ }
}
} else {
updateClientUids(new WorkSource());
@@ -1220,16 +1184,14 @@
List<WorkChain> goneChains = diffs[1];
if (newChains != null) {
- for (int i = 0; i < newChains.size(); ++i) {
- final WorkChain newChain = newChains.get(i);
+ for (WorkChain newChain : newChains) {
mAppOps.startOpNoThrow(AppOpsManager.OP_GPS, newChain.getAttributionUid(),
newChain.getAttributionTag());
}
}
if (goneChains != null) {
- for (int i = 0; i < goneChains.size(); i++) {
- final WorkChain goneChain = goneChains.get(i);
+ for (WorkChain goneChain : goneChains) {
mAppOps.finishOp(AppOpsManager.OP_GPS, goneChain.getAttributionUid(),
goneChain.getAttributionTag());
}
@@ -1262,32 +1224,27 @@
}
@Override
- public boolean sendExtraCommand(String command, Bundle extras) {
+ public void sendExtraCommand(String command, Bundle extras) {
long identity = Binder.clearCallingIdentity();
try {
- boolean result = false;
-
if ("delete_aiding_data".equals(command)) {
- result = deleteAidingData(extras);
+ deleteAidingData(extras);
} else if ("force_time_injection".equals(command)) {
requestUtcTime();
- result = true;
} else if ("force_xtra_injection".equals(command)) {
if (mSupportsXtra) {
xtraDownloadRequest();
- result = true;
}
} else {
Log.w(TAG, "sendExtraCommand: unknown command " + command);
}
- return result;
} finally {
Binder.restoreCallingIdentity(identity);
}
}
- private boolean deleteAidingData(Bundle extras) {
+ private void deleteAidingData(Bundle extras) {
int flags;
if (extras == null) {
@@ -1311,10 +1268,7 @@
if (flags != 0) {
native_delete_aiding_data(flags);
- return true;
}
-
- return false;
}
private void startNavigating(boolean singleShot) {
@@ -1358,7 +1312,7 @@
}
int interval = (hasCapability(GPS_CAPABILITY_SCHEDULING) ? mFixInterval : 1000);
- mLowPowerMode = (boolean) mProviderRequest.lowPowerMode;
+ mLowPowerMode = mProviderRequest.lowPowerMode;
if (!setPositionMode(mPositionMode, GPS_POSITION_RECURRENCE_PERIODIC,
interval, 0, 0, mLowPowerMode)) {
mStarted = false;
@@ -1415,10 +1369,7 @@
return ((mEngineCapabilities & capability) != 0);
}
-
- /**
- * called from native code to update our position.
- */
+ @NativeEntryPoint
private void reportLocation(boolean hasLatLong, Location location) {
sendMessage(REPORT_LOCATION, hasLatLong ? 1 : 0, location);
}
@@ -1444,11 +1395,7 @@
location.setElapsedRealtimeNanos(SystemClock.elapsedRealtimeNanos());
location.setExtras(mLocationExtras.getBundle());
- try {
- mILocationManager.reportLocation(location, false);
- } catch (RemoteException e) {
- Log.e(TAG, "RemoteException calling reportLocation");
- }
+ reportLocation(location);
if (mStarted) {
mGnssMetrics.logReceivedLocationStatus(hasLatLong);
@@ -1473,7 +1420,7 @@
}
// notify status listeners
- mListenerHelper.onFirstFix(mTimeToFirstFix);
+ mGnssStatusListenerHelper.onFirstFix(mTimeToFirstFix);
}
if (mSingleShot) {
@@ -1482,7 +1429,8 @@
if (mStarted && mStatus != LocationProvider.AVAILABLE) {
// For devices that use framework scheduling, a timer may be set to ensure we don't
- // spend too much power searching for a location, when the requested update rate is slow.
+ // spend too much power searching for a location, when the requested update rate is
+ // slow.
// As we just recievied a location, we'll cancel that timer.
if (!hasCapability(GPS_CAPABILITY_SCHEDULING) && mFixInterval < NO_FIX_TIMEOUT) {
mAlarmManager.cancel(mTimeoutIntent);
@@ -1502,9 +1450,7 @@
}
}
- /**
- * called from native code to update our status
- */
+ @NativeEntryPoint
private void reportStatus(int status) {
if (DEBUG) Log.v(TAG, "reportStatus status: " + status);
@@ -1512,22 +1458,19 @@
switch (status) {
case GPS_STATUS_SESSION_BEGIN:
mNavigating = true;
- mEngineOn = true;
break;
case GPS_STATUS_SESSION_END:
mNavigating = false;
break;
case GPS_STATUS_ENGINE_ON:
- mEngineOn = true;
break;
case GPS_STATUS_ENGINE_OFF:
- mEngineOn = false;
mNavigating = false;
break;
}
if (wasNavigating != mNavigating) {
- mListenerHelper.onStatusChanged(mNavigating);
+ mGnssStatusListenerHelper.onStatusChanged(mNavigating);
// send an intent to notify that the GPS has been enabled or disabled
Intent intent = new Intent(LocationManager.GPS_ENABLED_CHANGE_ACTION);
@@ -1538,17 +1481,15 @@
// Helper class to carry data to handler for reportSvStatus
private static class SvStatusInfo {
- public int mSvCount;
- public int[] mSvidWithFlags;
- public float[] mCn0s;
- public float[] mSvElevations;
- public float[] mSvAzimuths;
- public float[] mSvCarrierFreqs;
+ private int mSvCount;
+ private int[] mSvidWithFlags;
+ private float[] mCn0s;
+ private float[] mSvElevations;
+ private float[] mSvAzimuths;
+ private float[] mSvCarrierFreqs;
}
- /**
- * called from native code to update SV info
- */
+ @NativeEntryPoint
private void reportSvStatus(int svCount, int[] svidWithFlags, float[] cn0s,
float[] svElevations, float[] svAzimuths, float[] svCarrierFreqs) {
SvStatusInfo svStatusInfo = new SvStatusInfo();
@@ -1563,7 +1504,7 @@
}
private void handleReportSvStatus(SvStatusInfo info) {
- mListenerHelper.onSvStatusChanged(
+ mGnssStatusListenerHelper.onSvStatusChanged(
info.mSvCount,
info.mSvidWithFlags,
info.mCn0s,
@@ -1622,75 +1563,52 @@
}
}
- /**
- * called from native code to update AGPS status
- */
+ @NativeEntryPoint
private void reportAGpsStatus(int type, int status, byte[] ipaddr) {
mNetworkConnectivityHandler.onReportAGpsStatus(type, status, ipaddr);
}
- /**
- * called from native code to report NMEA data received
- */
+ @NativeEntryPoint
private void reportNmea(long timestamp) {
if (!mItarSpeedLimitExceeded) {
int length = native_read_nmea(mNmeaBuffer, mNmeaBuffer.length);
String nmea = new String(mNmeaBuffer, 0 /* offset */, length);
- mListenerHelper.onNmeaReceived(timestamp, nmea);
+ mGnssStatusListenerHelper.onNmeaReceived(timestamp, nmea);
}
}
- /**
- * called from native code - GNSS measurements callback
- */
+ @NativeEntryPoint
private void reportMeasurementData(GnssMeasurementsEvent event) {
if (!mItarSpeedLimitExceeded) {
// send to handler to allow native to return quickly
- mHandler.post(new Runnable() {
- @Override
- public void run() {
- mGnssMeasurementsProvider.onMeasurementsAvailable(event);
- }
- });
+ mHandler.post(() -> mGnssMeasurementsProvider.onMeasurementsAvailable(event));
}
}
- /**
- * called from native code - GNSS navigation message callback
- */
+ @NativeEntryPoint
private void reportNavigationMessage(GnssNavigationMessage event) {
if (!mItarSpeedLimitExceeded) {
// send to handler to allow native to return quickly
- mHandler.post(new Runnable() {
- @Override
- public void run() {
- mGnssNavigationMessageProvider.onNavigationMessageAvailable(event);
- }
- });
+ mHandler.post(() -> mGnssNavigationMessageProvider.onNavigationMessageAvailable(event));
}
}
- /**
- * called from native code to inform us what the GPS engine capabilities are
- */
+ @NativeEntryPoint
private void setEngineCapabilities(final int capabilities) {
// send to handler thread for fast native return, and in-order handling
- mHandler.post(new Runnable() {
- @Override
- public void run() {
- mEngineCapabilities = capabilities;
+ mHandler.post(() -> {
+ mEngineCapabilities = capabilities;
- if (hasCapability(GPS_CAPABILITY_ON_DEMAND_TIME)) {
- mNtpTimeHelper.enablePeriodicTimeInjection();
- requestUtcTime();
- }
-
- mGnssMeasurementsProvider.onCapabilitiesUpdated(hasCapability(
- GPS_CAPABILITY_MEASUREMENTS));
- mGnssNavigationMessageProvider.onCapabilitiesUpdated(hasCapability(
- GPS_CAPABILITY_NAV_MESSAGES));
- restartRequests();
+ if (hasCapability(GPS_CAPABILITY_ON_DEMAND_TIME)) {
+ mNtpTimeHelper.enablePeriodicTimeInjection();
+ requestUtcTime();
}
+
+ mGnssMeasurementsProvider.onCapabilitiesUpdated(hasCapability(
+ GPS_CAPABILITY_MEASUREMENTS));
+ mGnssNavigationMessageProvider.onCapabilitiesUpdated(hasCapability(
+ GPS_CAPABILITY_NAV_MESSAGES));
+ restartRequests();
});
}
@@ -1710,27 +1628,21 @@
updateRequirements();
}
- /**
- * Called from native code to inform us the hardware year.
- */
+ @NativeEntryPoint
private void setGnssYearOfHardware(final int yearOfHardware) {
// mHardwareYear is simply set here, to be read elsewhere, and is volatile for safe sync
if (DEBUG) Log.d(TAG, "setGnssYearOfHardware called with " + yearOfHardware);
mHardwareYear = yearOfHardware;
}
- /**
- * Called from native code to inform us the hardware model name.
- */
+ @NativeEntryPoint
private void setGnssHardwareModelName(final String modelName) {
// mHardwareModelName is simply set here, to be read elsewhere, and volatile for safe sync
if (DEBUG) Log.d(TAG, "setGnssModelName called with " + modelName);
mHardwareModelName = modelName;
}
- /**
- * Called from native code to inform us GNSS HAL service died.
- */
+ @NativeEntryPoint
private void reportGnssServiceDied() {
if (DEBUG) Log.d(TAG, "reportGnssServiceDied");
mHandler.post(() -> {
@@ -1750,6 +1662,7 @@
* Returns the year of underlying GPS hardware.
*/
int getGnssYearOfHardware();
+
/**
* Returns the model name of underlying GPS hardware.
*/
@@ -1765,6 +1678,7 @@
public int getGnssYearOfHardware() {
return mHardwareYear;
}
+
@Override
public String getGnssHardwareModelName() {
return mHardwareModelName;
@@ -1790,32 +1704,19 @@
* @hide
*/
public GnssMetricsProvider getGnssMetricsProvider() {
- return new GnssMetricsProvider() {
- @Override
- public String getGnssMetricsAsProtoString() {
- return mGnssMetrics.dumpGnssMetricsAsProtoString();
- }
- };
+ return () -> mGnssMetrics.dumpGnssMetricsAsProtoString();
}
- /**
- * called from native code - GNSS location batch callback
- */
+ @NativeEntryPoint
private void reportLocationBatch(Location[] locationArray) {
List<Location> locations = new ArrayList<>(Arrays.asList(locationArray));
if (DEBUG) {
Log.d(TAG, "Location batch of size " + locationArray.length + " reported");
}
- try {
- mILocationManager.reportLocationBatch(locations);
- } catch (RemoteException e) {
- Log.e(TAG, "RemoteException calling reportLocationBatch");
- }
+ reportLocation(locations);
}
- /**
- * called from native code to request XTRA data
- */
+ @NativeEntryPoint
private void xtraDownloadRequest() {
if (DEBUG) Log.d(TAG, "xtraDownloadRequest");
sendMessage(DOWNLOAD_XTRA_DATA, 0, null);
@@ -1824,7 +1725,7 @@
/**
* Converts the GPS HAL status to the internal Geofence Hardware status.
*/
- private int getGeofenceStatus(int status) {
+ private static int getGeofenceStatus(int status) {
switch (status) {
case GPS_GEOFENCE_OPERATION_SUCCESS:
return GeofenceHardware.GEOFENCE_SUCCESS;
@@ -1843,81 +1744,80 @@
}
}
- /**
- * Called from native to report GPS Geofence transition
- * All geofence callbacks are called on the same thread
- */
+ @NativeEntryPoint
private void reportGeofenceTransition(int geofenceId, Location location, int transition,
long transitionTimestamp) {
- if (mGeofenceHardwareImpl == null) {
- mGeofenceHardwareImpl = GeofenceHardwareImpl.getInstance(mContext);
- }
+ mHandler.post(() -> {
+ if (mGeofenceHardwareImpl == null) {
+ mGeofenceHardwareImpl = GeofenceHardwareImpl.getInstance(mContext);
+ }
- mGeofenceHardwareImpl.reportGeofenceTransition(
- geofenceId,
- location,
- transition,
- transitionTimestamp,
- GeofenceHardware.MONITORING_TYPE_GPS_HARDWARE,
- FusedBatchOptions.SourceTechnologies.GNSS);
+ mGeofenceHardwareImpl.reportGeofenceTransition(
+ geofenceId,
+ location,
+ transition,
+ transitionTimestamp,
+ GeofenceHardware.MONITORING_TYPE_GPS_HARDWARE,
+ FusedBatchOptions.SourceTechnologies.GNSS);
+ });
}
- /**
- * called from native code to report GPS status change.
- */
+ @NativeEntryPoint
private void reportGeofenceStatus(int status, Location location) {
- if (mGeofenceHardwareImpl == null) {
- mGeofenceHardwareImpl = GeofenceHardwareImpl.getInstance(mContext);
- }
- int monitorStatus = GeofenceHardware.MONITOR_CURRENTLY_UNAVAILABLE;
- if (status == GPS_GEOFENCE_AVAILABLE) {
- monitorStatus = GeofenceHardware.MONITOR_CURRENTLY_AVAILABLE;
- }
- mGeofenceHardwareImpl.reportGeofenceMonitorStatus(
- GeofenceHardware.MONITORING_TYPE_GPS_HARDWARE,
- monitorStatus,
- location,
- FusedBatchOptions.SourceTechnologies.GNSS);
+ mHandler.post(() -> {
+ if (mGeofenceHardwareImpl == null) {
+ mGeofenceHardwareImpl = GeofenceHardwareImpl.getInstance(mContext);
+ }
+ int monitorStatus = GeofenceHardware.MONITOR_CURRENTLY_UNAVAILABLE;
+ if (status == GPS_GEOFENCE_AVAILABLE) {
+ monitorStatus = GeofenceHardware.MONITOR_CURRENTLY_AVAILABLE;
+ }
+ mGeofenceHardwareImpl.reportGeofenceMonitorStatus(
+ GeofenceHardware.MONITORING_TYPE_GPS_HARDWARE,
+ monitorStatus,
+ location,
+ FusedBatchOptions.SourceTechnologies.GNSS);
+ });
}
- /**
- * called from native code - Geofence Add callback
- */
+ @NativeEntryPoint
private void reportGeofenceAddStatus(int geofenceId, int status) {
- if (mGeofenceHardwareImpl == null) {
- mGeofenceHardwareImpl = GeofenceHardwareImpl.getInstance(mContext);
- }
- mGeofenceHardwareImpl.reportGeofenceAddStatus(geofenceId, getGeofenceStatus(status));
+ mHandler.post(() -> {
+ if (mGeofenceHardwareImpl == null) {
+ mGeofenceHardwareImpl = GeofenceHardwareImpl.getInstance(mContext);
+ }
+ mGeofenceHardwareImpl.reportGeofenceAddStatus(geofenceId, getGeofenceStatus(status));
+ });
}
- /**
- * called from native code - Geofence Remove callback
- */
+ @NativeEntryPoint
private void reportGeofenceRemoveStatus(int geofenceId, int status) {
- if (mGeofenceHardwareImpl == null) {
- mGeofenceHardwareImpl = GeofenceHardwareImpl.getInstance(mContext);
- }
- mGeofenceHardwareImpl.reportGeofenceRemoveStatus(geofenceId, getGeofenceStatus(status));
+ mHandler.post(() -> {
+ if (mGeofenceHardwareImpl == null) {
+ mGeofenceHardwareImpl = GeofenceHardwareImpl.getInstance(mContext);
+ }
+ mGeofenceHardwareImpl.reportGeofenceRemoveStatus(geofenceId, getGeofenceStatus(status));
+ });
}
- /**
- * called from native code - Geofence Pause callback
- */
+ @NativeEntryPoint
private void reportGeofencePauseStatus(int geofenceId, int status) {
- if (mGeofenceHardwareImpl == null) {
- mGeofenceHardwareImpl = GeofenceHardwareImpl.getInstance(mContext);
- }
- mGeofenceHardwareImpl.reportGeofencePauseStatus(geofenceId, getGeofenceStatus(status));
+ mHandler.post(() -> {
+ if (mGeofenceHardwareImpl == null) {
+ mGeofenceHardwareImpl = GeofenceHardwareImpl.getInstance(mContext);
+ }
+ mGeofenceHardwareImpl.reportGeofencePauseStatus(geofenceId, getGeofenceStatus(status));
+ });
}
- /**
- * called from native code - Geofence Resume callback
- */
+ @NativeEntryPoint
private void reportGeofenceResumeStatus(int geofenceId, int status) {
- if (mGeofenceHardwareImpl == null) {
- mGeofenceHardwareImpl = GeofenceHardwareImpl.getInstance(mContext);
- }
- mGeofenceHardwareImpl.reportGeofenceResumeStatus(geofenceId, getGeofenceStatus(status));
+ mHandler.post(() -> {
+ if (mGeofenceHardwareImpl == null) {
+ mGeofenceHardwareImpl = GeofenceHardwareImpl.getInstance(mContext);
+ }
+ mGeofenceHardwareImpl.reportGeofenceResumeStatus(geofenceId, getGeofenceStatus(status));
+ });
}
//=============================================================
@@ -1942,7 +1842,8 @@
return mNetInitiatedListener;
}
- // Called by JNI function to report an NI request.
+ /** Reports a NI notification. */
+ @NativeEntryPoint
public void reportNiNotification(
int notificationId,
int niType,
@@ -1985,11 +1886,10 @@
}
/**
- * Called from native code to request set id info.
* We should be careful about receiving null string from the TelephonyManager,
* because sending null String to JNI function would cause a crash.
*/
-
+ @NativeEntryPoint
private void requestSetID(int flags) {
TelephonyManager phone = (TelephonyManager)
mContext.getSystemService(Context.TELEPHONY_SERVICE);
@@ -2018,9 +1918,7 @@
native_agps_set_id(type, data);
}
- /**
- * Called from native code to request location info.
- */
+ @NativeEntryPoint
private void requestLocation(boolean independentFromGnss) {
if (DEBUG) {
Log.d(TAG, "requestLocation. independentFromGnss: " + independentFromGnss);
@@ -2028,17 +1926,13 @@
sendMessage(REQUEST_LOCATION, 0, independentFromGnss);
}
- /**
- * Called from native code to request utc time info
- */
+ @NativeEntryPoint
private void requestUtcTime() {
if (DEBUG) Log.d(TAG, "utcTimeRequest");
sendMessage(INJECT_NTP_TIME, 0, null);
}
- /**
- * Called from native code to request reference location info
- */
+ @NativeEntryPoint
private void requestRefLocation() {
TelephonyManager phone = (TelephonyManager)
mContext.getSystemService(Context.TELEPHONY_SERVICE);
@@ -2092,11 +1986,7 @@
int message = msg.what;
switch (message) {
case ENABLE:
- if (msg.arg1 == 1) {
- handleEnable();
- } else {
- handleDisable();
- }
+ handleEnable();
break;
case SET_REQUEST:
GpsRequest gpsRequest = (GpsRequest) msg.obj;
@@ -2141,7 +2031,8 @@
}
/**
- * This method is bound to {@link #GnssLocationProvider(Context, ILocationManager, Looper)}.
+ * This method is bound to {@link #GnssLocationProvider(Context, LocationProviderManager,
+ * Looper)}.
* It is in charge of loading properties and registering for events that will be posted to
* this handler.
*/
@@ -2194,12 +2085,11 @@
(LocationManager) mContext.getSystemService(Context.LOCATION_SERVICE);
long minTime = 0;
float minDistance = 0;
- boolean oneShot = false;
LocationRequest request = LocationRequest.createFromDeprecatedProvider(
LocationManager.PASSIVE_PROVIDER,
minTime,
minDistance,
- oneShot);
+ false);
// Don't keep track of this request since it's done on behalf of other clients
// (which are kept track of separately).
request.setHideFromAppOps(true);
@@ -2207,11 +2097,14 @@
request,
new NetworkLocationListener(),
getLooper());
+
+ // enable gps provider, it will never be disabled (legacy behavior)
+ sendEmptyMessage(ENABLE);
}
}
private abstract class LocationChangeListener implements LocationListener {
- int numLocationUpdateRequest;
+ private int mNumLocationUpdateRequest;
@Override
public void onStatusChanged(String provider, int status, Bundle extras) {
diff --git a/services/core/java/com/android/server/location/GnssMeasurementsProvider.java b/services/core/java/com/android/server/location/GnssMeasurementsProvider.java
index 0add863..3e2ba87 100644
--- a/services/core/java/com/android/server/location/GnssMeasurementsProvider.java
+++ b/services/core/java/com/android/server/location/GnssMeasurementsProvider.java
@@ -38,7 +38,6 @@
private static final String TAG = "GnssMeasurementsProvider";
private static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG);
- private final Context mContext;
private final GnssMeasurementProviderNative mNative;
private boolean mIsCollectionStarted;
@@ -51,8 +50,7 @@
@VisibleForTesting
GnssMeasurementsProvider(Context context, Handler handler,
GnssMeasurementProviderNative aNative) {
- super(handler, TAG);
- mContext = context;
+ super(context, handler, TAG);
mNative = aNative;
}
@@ -98,9 +96,13 @@
}
public void onMeasurementsAvailable(final GnssMeasurementsEvent event) {
- ListenerOperation<IGnssMeasurementsListener> operation =
- listener -> listener.onGnssMeasurementsReceived(event);
- foreach(operation);
+ foreach((IGnssMeasurementsListener listener, int uid, String packageName) -> {
+ if (!hasPermission(uid, packageName)) {
+ logPermissionDisabledEventNotReported(TAG, packageName, "GNSS measurements");
+ return;
+ }
+ listener.onGnssMeasurementsReceived(event);
+ });
}
public void onCapabilitiesUpdated(boolean isGnssMeasurementsSupported) {
@@ -149,7 +151,8 @@
}
@Override
- public void execute(IGnssMeasurementsListener listener) throws RemoteException {
+ public void execute(IGnssMeasurementsListener listener,
+ int uid, String packageName) throws RemoteException {
listener.onStatusChanged(mStatus);
}
}
diff --git a/services/core/java/com/android/server/location/GnssNavigationMessageProvider.java b/services/core/java/com/android/server/location/GnssNavigationMessageProvider.java
index 1b4fd18..679919f 100644
--- a/services/core/java/com/android/server/location/GnssNavigationMessageProvider.java
+++ b/services/core/java/com/android/server/location/GnssNavigationMessageProvider.java
@@ -16,6 +16,7 @@
package com.android.server.location;
+import android.content.Context;
import android.location.GnssNavigationMessage;
import android.location.IGnssNavigationMessageListener;
import android.os.Handler;
@@ -39,13 +40,14 @@
private final GnssNavigationMessageProviderNative mNative;
private boolean mCollectionStarted;
- protected GnssNavigationMessageProvider(Handler handler) {
- this(handler, new GnssNavigationMessageProviderNative());
+ protected GnssNavigationMessageProvider(Context context, Handler handler) {
+ this(context, handler, new GnssNavigationMessageProviderNative());
}
@VisibleForTesting
- GnssNavigationMessageProvider(Handler handler, GnssNavigationMessageProviderNative aNative) {
- super(handler, TAG);
+ GnssNavigationMessageProvider(Context context, Handler handler,
+ GnssNavigationMessageProviderNative aNative) {
+ super(context, handler, TAG);
mNative = aNative;
}
@@ -84,15 +86,10 @@
}
public void onNavigationMessageAvailable(final GnssNavigationMessage event) {
- ListenerOperation<IGnssNavigationMessageListener> operation =
- new ListenerOperation<IGnssNavigationMessageListener>() {
- @Override
- public void execute(IGnssNavigationMessageListener listener)
- throws RemoteException {
- listener.onGnssNavigationMessageReceived(event);
- }
- };
- foreach(operation);
+ foreach((IGnssNavigationMessageListener listener, int uid, String packageName) -> {
+ listener.onGnssNavigationMessageReceived(event);
+ }
+ );
}
public void onCapabilitiesUpdated(boolean isGnssNavigationMessageSupported) {
@@ -138,7 +135,8 @@
}
@Override
- public void execute(IGnssNavigationMessageListener listener) throws RemoteException {
+ public void execute(IGnssNavigationMessageListener listener,
+ int uid, String packageName) throws RemoteException {
listener.onStatusChanged(mStatus);
}
}
diff --git a/services/core/java/com/android/server/location/GnssStatusListenerHelper.java b/services/core/java/com/android/server/location/GnssStatusListenerHelper.java
index 124220f..454dbdd 100644
--- a/services/core/java/com/android/server/location/GnssStatusListenerHelper.java
+++ b/services/core/java/com/android/server/location/GnssStatusListenerHelper.java
@@ -16,16 +16,20 @@
package com.android.server.location;
+import android.content.Context;
import android.location.IGnssStatusListener;
import android.os.Handler;
-import android.os.RemoteException;
+import android.util.Log;
/**
* Implementation of a handler for {@link IGnssStatusListener}.
*/
-abstract class GnssStatusListenerHelper extends RemoteListenerHelper<IGnssStatusListener> {
- protected GnssStatusListenerHelper(Handler handler) {
- super(handler, "GnssStatusListenerHelper");
+public abstract class GnssStatusListenerHelper extends RemoteListenerHelper<IGnssStatusListener> {
+ private static final String TAG = "GnssStatusListenerHelper";
+ private static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG);
+
+ protected GnssStatusListenerHelper(Context context, Handler handler) {
+ super(context, handler, TAG);
setSupported(GnssLocationProvider.isSupported());
}
@@ -43,33 +47,22 @@
}
public void onStatusChanged(boolean isNavigating) {
- Operation operation;
if (isNavigating) {
- operation = new Operation() {
- @Override
- public void execute(IGnssStatusListener listener) throws RemoteException {
- listener.onGnssStarted();
- }
- };
+ foreach((IGnssStatusListener listener, int uid, String packageName) -> {
+ listener.onGnssStarted();
+ });
} else {
- operation = new Operation() {
- @Override
- public void execute(IGnssStatusListener listener) throws RemoteException {
- listener.onGnssStopped();
- }
- };
+ foreach((IGnssStatusListener listener, int uid, String packageName) -> {
+ listener.onGnssStopped();
+ });
}
- foreach(operation);
}
public void onFirstFix(final int timeToFirstFix) {
- Operation operation = new Operation() {
- @Override
- public void execute(IGnssStatusListener listener) throws RemoteException {
- listener.onFirstFix(timeToFirstFix);
- }
- };
- foreach(operation);
+ foreach((IGnssStatusListener listener, int uid, String packageName) -> {
+ listener.onFirstFix(timeToFirstFix);
+ }
+ );
}
public void onSvStatusChanged(
@@ -79,30 +72,23 @@
final float[] elevations,
final float[] azimuths,
final float[] carrierFreqs) {
- Operation operation = new Operation() {
- @Override
- public void execute(IGnssStatusListener listener) throws RemoteException {
- listener.onSvStatusChanged(
- svCount,
- prnWithFlags,
- cn0s,
- elevations,
- azimuths,
- carrierFreqs);
+ foreach((IGnssStatusListener listener, int uid, String packageName) -> {
+ if (!hasPermission(uid, packageName)) {
+ logPermissionDisabledEventNotReported(TAG, packageName, "GNSS status");
+ return;
}
- };
- foreach(operation);
+ listener.onSvStatusChanged(svCount, prnWithFlags, cn0s, elevations, azimuths,
+ carrierFreqs);
+ });
}
public void onNmeaReceived(final long timestamp, final String nmea) {
- Operation operation = new Operation() {
- @Override
- public void execute(IGnssStatusListener listener) throws RemoteException {
- listener.onNmeaReceived(timestamp, nmea);
+ foreach((IGnssStatusListener listener, int uid, String packageName) -> {
+ if (!hasPermission(uid, packageName)) {
+ logPermissionDisabledEventNotReported(TAG, packageName, "NMEA");
+ return;
}
- };
- foreach(operation);
+ listener.onNmeaReceived(timestamp, nmea);
+ });
}
-
- private interface Operation extends ListenerOperation<IGnssStatusListener> {}
}
diff --git a/services/core/java/com/android/server/location/LocationProviderInterface.java b/services/core/java/com/android/server/location/LocationProviderInterface.java
deleted file mode 100644
index 6785964..0000000
--- a/services/core/java/com/android/server/location/LocationProviderInterface.java
+++ /dev/null
@@ -1,78 +0,0 @@
-/*
- * Copyright (C) 2010 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.server.location;
-
-import android.location.LocationProvider;
-import android.os.Bundle;
-import android.os.WorkSource;
-
-import com.android.internal.location.ProviderProperties;
-import com.android.internal.location.ProviderRequest;
-
-import java.io.FileDescriptor;
-import java.io.PrintWriter;
-
-/**
- * Location Manager's interface for location providers.
- * @hide
- */
-public abstract class LocationProviderInterface {
-
- /** Get name. */
- public abstract String getName();
-
- /** Enable. */
- public abstract void enable();
-
- /** Disable. */
- public abstract void disable();
-
- /** Is enabled. */
- public abstract boolean isEnabled();
-
- /** Set request. */
- public abstract void setRequest(ProviderRequest request, WorkSource source);
-
- /** dump. */
- public abstract void dump(FileDescriptor fd, PrintWriter pw, String[] args);
-
- /** Get properties. */
- public abstract ProviderProperties getProperties();
-
- /**
- * Get status.
- *
- * @deprecated Will be removed in a future release.
- */
- @Deprecated
- public int getStatus(Bundle extras) {
- return LocationProvider.AVAILABLE;
- }
-
- /**
- * Get status update time.
- *
- * @deprecated Will be removed in a future release.
- */
- @Deprecated
- public long getStatusUpdateTime() {
- return 0;
- }
-
- /** Send extra command. */
- public abstract boolean sendExtraCommand(String command, Bundle extras);
-}
diff --git a/services/core/java/com/android/server/location/LocationProviderProxy.java b/services/core/java/com/android/server/location/LocationProviderProxy.java
index b408414..dfcef70 100644
--- a/services/core/java/com/android/server/location/LocationProviderProxy.java
+++ b/services/core/java/com/android/server/location/LocationProviderProxy.java
@@ -18,6 +18,7 @@
import android.annotation.Nullable;
import android.content.Context;
+import android.location.Location;
import android.location.LocationProvider;
import android.os.Bundle;
import android.os.IBinder;
@@ -27,6 +28,7 @@
import com.android.internal.annotations.GuardedBy;
import com.android.internal.location.ILocationProvider;
+import com.android.internal.location.ILocationProviderManager;
import com.android.internal.location.ProviderProperties;
import com.android.internal.location.ProviderRequest;
import com.android.internal.os.BackgroundThread;
@@ -41,21 +43,35 @@
/**
* Proxy for ILocationProvider implementations.
*/
-public class LocationProviderProxy extends LocationProviderInterface {
+public class LocationProviderProxy extends AbstractLocationProvider {
+
private static final String TAG = "LocationProviderProxy";
private static final boolean D = LocationManagerService.D;
- private final ServiceWatcher mServiceWatcher;
-
- private final String mName;
-
// used to ensure that updates to mRequest and mWorkSource are atomic
private final Object mRequestLock = new Object();
+ private final ServiceWatcher mServiceWatcher;
- private volatile boolean mEnabled = false;
- @Nullable
- private volatile ProviderProperties mProperties;
+ private final ILocationProviderManager.Stub mManager = new ILocationProviderManager.Stub() {
+ // executed on binder thread
+ @Override
+ public void onSetEnabled(boolean enabled) {
+ LocationProviderProxy.this.setEnabled(enabled);
+ }
+
+ // executed on binder thread
+ @Override
+ public void onSetProperties(ProviderProperties properties) {
+ LocationProviderProxy.this.setProperties(properties);
+ }
+
+ // executed on binder thread
+ @Override
+ public void onReportLocation(Location location) {
+ LocationProviderProxy.this.reportLocation(location);
+ }
+ };
@GuardedBy("mRequestLock")
@Nullable
@@ -69,10 +85,10 @@
*/
@Nullable
public static LocationProviderProxy createAndBind(
- Context context, String name, String action,
+ Context context, LocationProviderManager locationProviderManager, String action,
int overlaySwitchResId, int defaultServicePackageNameResId,
int initialPackageNamesResId) {
- LocationProviderProxy proxy = new LocationProviderProxy(context, name,
+ LocationProviderProxy proxy = new LocationProviderProxy(context, locationProviderManager,
action, overlaySwitchResId, defaultServicePackageNameResId,
initialPackageNamesResId);
if (proxy.bind()) {
@@ -82,21 +98,27 @@
}
}
- private LocationProviderProxy(Context context, String name,
+ private LocationProviderProxy(Context context, LocationProviderManager locationProviderManager,
String action, int overlaySwitchResId, int defaultServicePackageNameResId,
int initialPackageNamesResId) {
+ super(locationProviderManager, false);
mServiceWatcher = new ServiceWatcher(context, TAG, action, overlaySwitchResId,
defaultServicePackageNameResId, initialPackageNamesResId,
BackgroundThread.getHandler()) {
+
@Override
protected void onBind() {
runOnBinder(LocationProviderProxy.this::initializeService);
}
- };
- mName = name;
- mProperties = null;
+ @Override
+ protected void onUnbind() {
+ setEnabled(false);
+ setProperties(null);
+ }
+ };
+
mRequest = null;
mWorkSource = new WorkSource();
}
@@ -107,84 +129,27 @@
private void initializeService(IBinder binder) {
ILocationProvider service = ILocationProvider.Stub.asInterface(binder);
- if (D) Log.d(TAG, "applying state to connected service");
-
- ProviderProperties[] properties = new ProviderProperties[1];
- ProviderRequest request;
- WorkSource source;
- synchronized (mRequestLock) {
- request = mRequest;
- source = mWorkSource;
- }
+ if (D) Log.d(TAG, "applying state to connected service " + mServiceWatcher);
try {
- // load properties from provider
- properties[0] = service.getProperties();
- if (properties[0] == null) {
- Log.e(TAG, mServiceWatcher.getCurrentPackageName()
- + " has invalid location provider properties");
- }
+ service.setLocationProviderManager(mManager);
- // apply current state to new service
- if (mEnabled) {
- service.enable();
- if (request != null) {
- service.setRequest(request, source);
+ synchronized (mRequestLock) {
+ if (mRequest != null) {
+ service.setRequest(mRequest, mWorkSource);
}
}
} catch (RemoteException e) {
Log.w(TAG, e);
}
-
- mProperties = properties[0];
}
+ @Nullable
public String getConnectedPackageName() {
return mServiceWatcher.getCurrentPackageName();
}
@Override
- public String getName() {
- return mName;
- }
-
- @Override
- public ProviderProperties getProperties() {
- return mProperties;
- }
-
- @Override
- public void enable() {
- mEnabled = true;
- mServiceWatcher.runOnBinder(binder -> {
- ILocationProvider service = ILocationProvider.Stub.asInterface(binder);
- try {
- service.enable();
- } catch (RemoteException e) {
- Log.w(TAG, e);
- }
- });
- }
-
- @Override
- public void disable() {
- mEnabled = false;
- mServiceWatcher.runOnBinder(binder -> {
- ILocationProvider service = ILocationProvider.Stub.asInterface(binder);
- try {
- service.disable();
- } catch (RemoteException e) {
- Log.w(TAG, e);
- }
- });
- }
-
- @Override
- public boolean isEnabled() {
- return mEnabled;
- }
-
- @Override
public void setRequest(ProviderRequest request, WorkSource source) {
synchronized (mRequestLock) {
mRequest = request;
@@ -202,60 +167,53 @@
@Override
public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
- pw.append("REMOTE SERVICE");
- pw.append(" name=").append(mName);
- pw.append(" pkg=").append(mServiceWatcher.getCurrentPackageName());
- pw.append(" version=").append(Integer.toString(mServiceWatcher.getCurrentPackageVersion()));
- pw.append('\n');
+ pw.println(" service=" + mServiceWatcher);
mServiceWatcher.runOnBinder(binder -> {
- ILocationProvider service = ILocationProvider.Stub.asInterface(binder);
try {
- TransferPipe.dumpAsync(service.asBinder(), fd, args);
+ TransferPipe.dumpAsync(binder, fd, args);
} catch (IOException | RemoteException e) {
- pw.println("Failed to dump location provider: " + e);
+ pw.println(" failed to dump location provider: " + e);
}
});
}
@Override
public int getStatus(Bundle extras) {
- int[] result = new int[]{LocationProvider.TEMPORARILY_UNAVAILABLE};
+ int[] status = new int[] {LocationProvider.TEMPORARILY_UNAVAILABLE};
mServiceWatcher.runOnBinder(binder -> {
ILocationProvider service = ILocationProvider.Stub.asInterface(binder);
try {
- result[0] = service.getStatus(extras);
+ status[0] = service.getStatus(extras);
} catch (RemoteException e) {
Log.w(TAG, e);
}
});
- return result[0];
+ return status[0];
}
@Override
public long getStatusUpdateTime() {
- long[] result = new long[]{0L};
+ long[] updateTime = new long[] {0L};
mServiceWatcher.runOnBinder(binder -> {
ILocationProvider service = ILocationProvider.Stub.asInterface(binder);
try {
- result[0] = service.getStatusUpdateTime();
+ updateTime[0] = service.getStatusUpdateTime();
} catch (RemoteException e) {
Log.w(TAG, e);
}
});
- return result[0];
+ return updateTime[0];
}
@Override
- public boolean sendExtraCommand(String command, Bundle extras) {
- boolean[] result = new boolean[]{false};
+ public void sendExtraCommand(String command, Bundle extras) {
mServiceWatcher.runOnBinder(binder -> {
ILocationProvider service = ILocationProvider.Stub.asInterface(binder);
try {
- result[0] = service.sendExtraCommand(command, extras);
+ service.sendExtraCommand(command, extras);
} catch (RemoteException e) {
Log.w(TAG, e);
}
});
- return result[0];
}
}
diff --git a/services/core/java/com/android/server/location/MockProvider.java b/services/core/java/com/android/server/location/MockProvider.java
index 145aee3..bfbebf7 100644
--- a/services/core/java/com/android/server/location/MockProvider.java
+++ b/services/core/java/com/android/server/location/MockProvider.java
@@ -16,14 +16,11 @@
package com.android.server.location;
-import android.location.ILocationManager;
+import android.annotation.Nullable;
import android.location.Location;
import android.location.LocationProvider;
import android.os.Bundle;
-import android.os.RemoteException;
import android.os.WorkSource;
-import android.util.Log;
-import android.util.PrintWriterPrinter;
import com.android.internal.location.ProviderProperties;
import com.android.internal.location.ProviderRequest;
@@ -36,63 +33,57 @@
*
* {@hide}
*/
-public class MockProvider extends LocationProviderInterface {
- private final String mName;
- private final ProviderProperties mProperties;
- private final ILocationManager mLocationManager;
+public class MockProvider extends AbstractLocationProvider {
- private final Location mLocation;
-
- private boolean mHasLocation;
private boolean mEnabled;
-
-
+ @Nullable private Location mLocation;
private int mStatus;
private long mStatusUpdateTime;
private Bundle mExtras;
- private static final String TAG = "MockProvider";
+ public MockProvider(
+ LocationProviderManager locationProviderManager, ProviderProperties properties) {
+ super(locationProviderManager, true);
- public MockProvider(String name, ILocationManager locationManager,
- ProviderProperties properties) {
- if (properties == null) throw new NullPointerException("properties is null");
-
- mName = name;
- mLocationManager = locationManager;
- mProperties = properties;
- mLocation = new Location(name);
-
- mStatus = LocationProvider.AVAILABLE;
- mStatusUpdateTime = 0L;
- mExtras = null;
- }
-
- @Override
- public String getName() {
- return mName;
- }
-
- @Override
- public ProviderProperties getProperties() {
- return mProperties;
- }
-
- @Override
- public void disable() {
- mEnabled = false;
- }
-
- @Override
- public void enable() {
mEnabled = true;
+ mLocation = null;
+ mStatus = LocationProvider.AVAILABLE;
+ mStatusUpdateTime = 0;
+ mExtras = null;
+
+ setProperties(properties);
+ }
+
+ /** Sets the enabled state of this mock provider. */
+ public void setEnabled(boolean enabled) {
+ mEnabled = enabled;
+ super.setEnabled(enabled);
+ }
+
+ /** Sets the location to report for this mock provider. */
+ public void setLocation(Location l) {
+ mLocation = new Location(l);
+ if (mEnabled) {
+ reportLocation(l);
+ }
+ }
+
+ /** Sets the status for this mock provider. */
+ public void setStatus(int status, Bundle extras, long updateTime) {
+ mStatus = status;
+ mStatusUpdateTime = updateTime;
+ mExtras = extras;
}
@Override
- public boolean isEnabled() {
- return mEnabled;
+ public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
+ pw.println(" last location=" + mLocation);
}
@Override
+ public void setRequest(ProviderRequest request, WorkSource source) {}
+
+ @Override
public int getStatus(Bundle extras) {
if (mExtras != null) {
extras.clear();
@@ -107,50 +98,6 @@
return mStatusUpdateTime;
}
- public void setLocation(Location l) {
- mLocation.set(l);
- mHasLocation = true;
- if (mEnabled) {
- try {
- mLocationManager.reportLocation(mLocation, false);
- } catch (RemoteException e) {
- Log.e(TAG, "RemoteException calling reportLocation");
- }
- }
- }
-
- public void clearLocation() {
- mHasLocation = false;
- }
-
- /**
- * @deprecated Will be removed in a future release.
- */
- @Deprecated
- public void setStatus(int status, Bundle extras, long updateTime) {
- mStatus = status;
- mStatusUpdateTime = updateTime;
- mExtras = extras;
- }
-
@Override
- public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
- dump(pw, "");
- }
-
- public void dump(PrintWriter pw, String prefix) {
- pw.println(prefix + mName);
- pw.println(prefix + "mHasLocation=" + mHasLocation);
- pw.println(prefix + "mLocation:");
- mLocation.dump(new PrintWriterPrinter(pw), prefix + " ");
- pw.println(prefix + "mExtras=" + mExtras);
- }
-
- @Override
- public void setRequest(ProviderRequest request, WorkSource source) { }
-
- @Override
- public boolean sendExtraCommand(String command, Bundle extras) {
- return false;
- }
+ public void sendExtraCommand(String command, Bundle extras) {}
}
diff --git a/services/core/java/com/android/server/location/PassiveProvider.java b/services/core/java/com/android/server/location/PassiveProvider.java
index 99c9214..70d64b0 100644
--- a/services/core/java/com/android/server/location/PassiveProvider.java
+++ b/services/core/java/com/android/server/location/PassiveProvider.java
@@ -17,13 +17,9 @@
package com.android.server.location;
import android.location.Criteria;
-import android.location.ILocationManager;
import android.location.Location;
-import android.location.LocationManager;
import android.os.Bundle;
-import android.os.RemoteException;
import android.os.WorkSource;
-import android.util.Log;
import com.android.internal.location.ProviderProperties;
import com.android.internal.location.ProviderRequest;
@@ -38,41 +34,20 @@
*
* {@hide}
*/
-public class PassiveProvider extends LocationProviderInterface {
- private static final String TAG = "PassiveProvider";
+public class PassiveProvider extends AbstractLocationProvider {
private static final ProviderProperties PROPERTIES = new ProviderProperties(
false, false, false, false, false, false, false,
Criteria.POWER_LOW, Criteria.ACCURACY_COARSE);
- private final ILocationManager mLocationManager;
private boolean mReportLocation;
- public PassiveProvider(ILocationManager locationManager) {
- mLocationManager = locationManager;
- }
+ public PassiveProvider(LocationProviderManager locationProviderManager) {
+ super(locationProviderManager, true);
- @Override
- public String getName() {
- return LocationManager.PASSIVE_PROVIDER;
- }
+ mReportLocation = false;
- @Override
- public ProviderProperties getProperties() {
- return PROPERTIES;
- }
-
- @Override
- public boolean isEnabled() {
- return true;
- }
-
- @Override
- public void enable() {
- }
-
- @Override
- public void disable() {
+ setProperties(PROPERTIES);
}
@Override
@@ -82,22 +57,15 @@
public void updateLocation(Location location) {
if (mReportLocation) {
- try {
- // pass the location back to the location manager
- mLocationManager.reportLocation(location, true);
- } catch (RemoteException e) {
- Log.e(TAG, "RemoteException calling reportLocation");
- }
+ reportLocation(location);
}
}
@Override
- public boolean sendExtraCommand(String command, Bundle extras) {
- return false;
- }
+ public void sendExtraCommand(String command, Bundle extras) {}
@Override
public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
- pw.println("mReportLocation=" + mReportLocation);
+ pw.println(" report location=" + mReportLocation);
}
}
diff --git a/services/core/java/com/android/server/location/RemoteListenerHelper.java b/services/core/java/com/android/server/location/RemoteListenerHelper.java
index fcdb9d1..37d43fc 100644
--- a/services/core/java/com/android/server/location/RemoteListenerHelper.java
+++ b/services/core/java/com/android/server/location/RemoteListenerHelper.java
@@ -17,6 +17,8 @@
package com.android.server.location;
import android.annotation.NonNull;
+import android.app.AppOpsManager;
+import android.content.Context;
import android.os.Handler;
import android.os.IBinder;
import android.os.IInterface;
@@ -46,6 +48,9 @@
private final Map<IBinder, LinkedListener> mListenerMap = new HashMap<>();
+ protected final Context mContext;
+ protected final AppOpsManager mAppOps;
+
private volatile boolean mIsRegistered; // must access only on handler thread, or read-only
private boolean mHasIsSupported;
@@ -53,10 +58,12 @@
private int mLastReportedResult = RESULT_UNKNOWN;
- protected RemoteListenerHelper(Handler handler, String name) {
+ protected RemoteListenerHelper(Context context, Handler handler, String name) {
Preconditions.checkNotNull(name);
mHandler = handler;
mTag = name;
+ mContext = context;
+ mAppOps = (AppOpsManager) context.getSystemService(Context.APP_OPS_SERVICE);
}
// read-only access for a dump() thread assured via volatile
@@ -64,10 +71,10 @@
return mIsRegistered;
}
- public boolean addListener(@NonNull TListener listener) {
+ public boolean addListener(@NonNull TListener listener, int uid, String packageName) {
Preconditions.checkNotNull(listener, "Attempted to register a 'null' listener.");
IBinder binder = listener.asBinder();
- LinkedListener deathListener = new LinkedListener(listener);
+ LinkedListener deathListener = new LinkedListener(listener, uid, packageName);
synchronized (mListenerMap) {
if (mListenerMap.containsKey(binder)) {
// listener already added
@@ -102,7 +109,7 @@
// asynchronously in the future
return true;
}
- post(listener, getHandlerOperation(result));
+ post(deathListener, getHandlerOperation(result));
}
return true;
}
@@ -130,7 +137,7 @@
protected abstract ListenerOperation<TListener> getHandlerOperation(int result);
protected interface ListenerOperation<TListener extends IInterface> {
- void execute(TListener listener) throws RemoteException;
+ void execute(TListener listener, int uid, String packageName) throws RemoteException;
}
protected void foreach(ListenerOperation<TListener> operation) {
@@ -170,15 +177,28 @@
}
}
- private void foreachUnsafe(ListenerOperation<TListener> operation) {
- for (LinkedListener linkedListener : mListenerMap.values()) {
- post(linkedListener.getUnderlyingListener(), operation);
+ protected boolean hasPermission(int uid, String packageName) {
+ return mAppOps.noteOpNoThrow(AppOpsManager.OP_FINE_LOCATION, uid, packageName)
+ == AppOpsManager.MODE_ALLOWED;
+ }
+
+ protected void logPermissionDisabledEventNotReported(String tag, String packageName,
+ String event) {
+ if (Log.isLoggable(tag, Log.DEBUG)) {
+ Log.d(tag, "Location permission disabled. Skipping " + event + " reporting for app: "
+ + packageName);
}
}
- private void post(TListener listener, ListenerOperation<TListener> operation) {
+ private void foreachUnsafe(ListenerOperation<TListener> operation) {
+ for (LinkedListener linkedListener : mListenerMap.values()) {
+ post(linkedListener, operation);
+ }
+ }
+
+ private void post(LinkedListener linkedListener, ListenerOperation<TListener> operation) {
if (operation != null) {
- mHandler.post(new HandlerRunnable(listener, operation));
+ mHandler.post(new HandlerRunnable(linkedListener, operation));
}
}
@@ -193,13 +213,9 @@
}
if (!mIsRegistered) {
// post back a failure
- mHandler.post(new Runnable() {
- @Override
- public void run() {
- synchronized (mListenerMap) {
- ListenerOperation<TListener> operation = getHandlerOperation(registrationState);
- foreachUnsafe(operation);
- }
+ mHandler.post(() -> {
+ synchronized (mListenerMap) {
+ foreachUnsafe(getHandlerOperation(registrationState));
}
});
}
@@ -208,16 +224,14 @@
}
private void tryUnregister() {
- mHandler.post(new Runnable() {
- @Override
- public void run() {
- if (!mIsRegistered) {
- return;
+ mHandler.post(() -> {
+ if (!mIsRegistered) {
+ return;
+ }
+ unregisterFromService();
+ mIsRegistered = false;
}
- unregisterFromService();
- mIsRegistered = false;
- }
- });
+ );
}
private int calculateCurrentResultUnsafe() {
@@ -240,14 +254,13 @@
private class LinkedListener implements IBinder.DeathRecipient {
private final TListener mListener;
+ private final int mUid;
+ private final String mPackageName;
- public LinkedListener(@NonNull TListener listener) {
+ LinkedListener(@NonNull TListener listener, int uid, String packageName) {
mListener = listener;
- }
-
- @NonNull
- public TListener getUnderlyingListener() {
- return mListener;
+ mUid = uid;
+ mPackageName = packageName;
}
@Override
@@ -258,18 +271,19 @@
}
private class HandlerRunnable implements Runnable {
- private final TListener mListener;
+ private final LinkedListener mLinkedListener;
private final ListenerOperation<TListener> mOperation;
- public HandlerRunnable(TListener listener, ListenerOperation<TListener> operation) {
- mListener = listener;
+ HandlerRunnable(LinkedListener linkedListener, ListenerOperation<TListener> operation) {
+ mLinkedListener = linkedListener;
mOperation = operation;
}
@Override
public void run() {
try {
- mOperation.execute(mListener);
+ mOperation.execute(mLinkedListener.mListener, mLinkedListener.mUid,
+ mLinkedListener.mPackageName);
} catch (RemoteException e) {
Log.v(mTag, "Error in monitored listener.", e);
}
diff --git a/services/core/java/com/android/server/locksettings/SyntheticPasswordManager.java b/services/core/java/com/android/server/locksettings/SyntheticPasswordManager.java
index d32c299..0e195bc 100644
--- a/services/core/java/com/android/server/locksettings/SyntheticPasswordManager.java
+++ b/services/core/java/com/android/server/locksettings/SyntheticPasswordManager.java
@@ -29,6 +29,7 @@
import android.os.RemoteException;
import android.os.UserManager;
import android.security.GateKeeper;
+import android.security.Scrypt;
import android.service.gatekeeper.GateKeeperResponse;
import android.service.gatekeeper.IGateKeeperService;
import android.util.ArrayMap;
@@ -1173,11 +1174,10 @@
}
protected byte[] scrypt(String password, byte[] salt, int N, int r, int p, int outLen) {
- return nativeScrypt(password.getBytes(), salt, N, r, p, outLen);
+ return new Scrypt().scrypt(password.getBytes(), salt, N, r, p, outLen);
}
native long nativeSidFromPasswordHandle(byte[] handle);
- native byte[] nativeScrypt(byte[] password, byte[] salt, int N, int r, int p, int outLen);
protected static ArrayList<Byte> toByteArrayList(byte[] data) {
ArrayList<Byte> result = new ArrayList<Byte>(data.length);
diff --git a/services/core/java/com/android/server/net/NetworkStatsRecorder.java b/services/core/java/com/android/server/net/NetworkStatsRecorder.java
index a16dcf3..a2e7e0c 100644
--- a/services/core/java/com/android/server/net/NetworkStatsRecorder.java
+++ b/services/core/java/com/android/server/net/NetworkStatsRecorder.java
@@ -352,7 +352,7 @@
// Clear UID from current stats snapshot
if (mLastSnapshot != null) {
- mLastSnapshot = mLastSnapshot.withoutUids(uids);
+ mLastSnapshot.removeUids(uids);
}
final NetworkStatsCollection complete = mComplete != null ? mComplete.get() : null;
diff --git a/services/core/java/com/android/server/notification/NotificationManagerService.java b/services/core/java/com/android/server/notification/NotificationManagerService.java
index 95e1962..f19ecf3 100644
--- a/services/core/java/com/android/server/notification/NotificationManagerService.java
+++ b/services/core/java/com/android/server/notification/NotificationManagerService.java
@@ -5511,7 +5511,12 @@
{
mHandler.removeCallbacksAndMessages(r);
Message m = Message.obtain(mHandler, MESSAGE_DURATION_REACHED, r);
- long delay = r.duration == Toast.LENGTH_LONG ? LONG_DELAY : SHORT_DELAY;
+ int delay = r.duration == Toast.LENGTH_LONG ? LONG_DELAY : SHORT_DELAY;
+ // Accessibility users may need longer timeout duration. This api compares original delay
+ // with user's preference and return longer one. It returns original delay if there's no
+ // preference.
+ delay = mAccessibilityManager.getRecommendedTimeoutMillis(delay,
+ AccessibilityManager.FLAG_CONTENT_TEXT);
mHandler.sendMessageDelayed(m, delay);
}
diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java
index dca92ea..888675c 100644
--- a/services/core/java/com/android/server/pm/PackageManagerService.java
+++ b/services/core/java/com/android/server/pm/PackageManagerService.java
@@ -1301,6 +1301,7 @@
final @Nullable String mSetupWizardPackage;
final @Nullable String mStorageManagerPackage;
final @Nullable String mSystemTextClassifierPackage;
+ final @Nullable String mWellbeingPackage;
final @NonNull String mServicesSystemSharedLibraryPackageName;
final @NonNull String mSharedSystemSharedLibraryPackageName;
@@ -2790,6 +2791,8 @@
mSystemTextClassifierPackage = getSystemTextClassifierPackageName();
+ mWellbeingPackage = getWellbeingPackageName();
+
// Now that we know all of the shared libraries, update all clients to have
// the correct library paths.
updateAllSharedLibrariesLPw(null);
@@ -11258,7 +11261,7 @@
== UsesPermissionInfo.USAGE_UNDEFINED
|| upi.getDataRetention() == UsesPermissionInfo.RETENTION_UNDEFINED) {
// STOPSHIP: Make this throw
- Slog.wtf(TAG, "Package " + pkg.packageName + " does not provide usage "
+ Slog.e(TAG, "Package " + pkg.packageName + " does not provide usage "
+ "information for permission " + upi.getPermission()
+ ". This will be a fatal error in Q.");
}
@@ -12836,16 +12839,17 @@
final List<String> unactionedPackages = new ArrayList<>(packageNames.length);
final long callingId = Binder.clearCallingIdentity();
try {
- synchronized (mPackages) {
- for (int i = 0; i < packageNames.length; i++) {
- final String packageName = packageNames[i];
- if (callingPackage.equals(packageName)) {
- Slog.w(TAG, "Calling package: " + callingPackage + " trying to "
- + (suspended ? "" : "un") + "suspend itself. Ignoring");
- unactionedPackages.add(packageName);
- continue;
- }
- final PackageSetting pkgSetting = mSettings.mPackages.get(packageName);
+ for (int i = 0; i < packageNames.length; i++) {
+ final String packageName = packageNames[i];
+ if (callingPackage.equals(packageName)) {
+ Slog.w(TAG, "Calling package: " + callingPackage + " trying to "
+ + (suspended ? "" : "un") + "suspend itself. Ignoring");
+ unactionedPackages.add(packageName);
+ continue;
+ }
+ PackageSetting pkgSetting;
+ synchronized (mPackages) {
+ pkgSetting = mSettings.mPackages.get(packageName);
if (pkgSetting == null
|| filterAppAccessLPr(pkgSetting, callingUid, userId)) {
Slog.w(TAG, "Could not find package setting for package: " + packageName
@@ -12853,15 +12857,20 @@
unactionedPackages.add(packageName);
continue;
}
- if (suspended && !canSuspendPackageForUserLocked(packageName, userId)) {
- unactionedPackages.add(packageName);
- continue;
- }
- pkgSetting.setSuspended(suspended, callingPackage, dialogInfo, appExtras,
- launcherExtras, userId);
- changedPackagesList.add(packageName);
- changedUids.add(UserHandle.getUid(userId, pkgSetting.appId));
}
+ if (suspended && !canSuspendPackageForUserInternal(packageName, userId)) {
+ unactionedPackages.add(packageName);
+ continue;
+ }
+ synchronized (mPackages) {
+ pkgSetting = mSettings.mPackages.get(packageName);
+ if (pkgSetting != null) {
+ pkgSetting.setSuspended(suspended, callingPackage, dialogInfo, appExtras,
+ launcherExtras, userId);
+ }
+ }
+ changedPackagesList.add(packageName);
+ changedUids.add(UserHandle.getUid(userId, pkgSetting.appId));
}
} finally {
Binder.restoreCallingIdentity(callingId);
@@ -13018,16 +13027,13 @@
}
final long identity = Binder.clearCallingIdentity();
try {
- synchronized (mPackages) {
- return canSuspendPackageForUserLocked(packageName, userId);
- }
+ return canSuspendPackageForUserInternal(packageName, userId);
} finally {
Binder.restoreCallingIdentity(identity);
}
}
- @GuardedBy("mPackages")
- private boolean canSuspendPackageForUserLocked(String packageName, int userId) {
+ private boolean canSuspendPackageForUserInternal(String packageName, int userId) {
if (isPackageDeviceAdmin(packageName, userId)) {
Slog.w(TAG, "Cannot suspend package \"" + packageName
+ "\": has an active device admin");
@@ -13071,21 +13077,23 @@
return false;
}
- if (mProtectedPackages.isPackageStateProtected(userId, packageName)) {
- Slog.w(TAG, "Cannot suspend package \"" + packageName
- + "\": protected package");
- return false;
- }
+ synchronized (mPackages) {
+ if (mProtectedPackages.isPackageStateProtected(userId, packageName)) {
+ Slog.w(TAG, "Cannot suspend package \"" + packageName
+ + "\": protected package");
+ return false;
+ }
- // Cannot suspend static shared libs as they are considered
- // a part of the using app (emulating static linking). Also
- // static libs are installed always on internal storage.
- PackageParser.Package pkg = mPackages.get(packageName);
- if (pkg != null && pkg.applicationInfo.isStaticSharedLibrary()) {
- Slog.w(TAG, "Cannot suspend package: " + packageName
- + " providing static shared library: "
- + pkg.staticSharedLibName);
- return false;
+ // Cannot suspend static shared libs as they are considered
+ // a part of the using app (emulating static linking). Also
+ // static libs are installed always on internal storage.
+ PackageParser.Package pkg = mPackages.get(packageName);
+ if (pkg != null && pkg.applicationInfo.isStaticSharedLibrary()) {
+ Slog.w(TAG, "Cannot suspend package: " + packageName
+ + " providing static shared library: "
+ + pkg.staticSharedLibName);
+ return false;
+ }
}
if (PLATFORM_PACKAGE_NAME.equals(packageName)) {
@@ -18302,6 +18310,10 @@
continue;
}
+ if (bp.isRemoved()) {
+ continue;
+ }
+
// If shared user we just reset the state to which only this app contributed.
if (ps.sharedUser != null) {
boolean used = false;
@@ -19559,6 +19571,11 @@
}
@Override
+ public String getWellbeingPackageName() {
+ return mContext.getString(R.string.config_defaultWellbeingPackage);
+ }
+
+ @Override
public void setApplicationEnabledSetting(String appPackageName,
int newState, int flags, int userId, String callingPackage) {
if (!sUserManager.exists(userId)) return;
@@ -22714,6 +22731,8 @@
return mSystemTextClassifierPackage;
case PackageManagerInternal.PACKAGE_PERMISSION_CONTROLLER:
return mRequiredPermissionControllerPackage;
+ case PackageManagerInternal.PACKAGE_WELLBEING:
+ return mWellbeingPackage;
}
return null;
}
diff --git a/services/core/java/com/android/server/pm/permission/BasePermission.java b/services/core/java/com/android/server/pm/permission/BasePermission.java
index 2d583ca3..996f42b 100644
--- a/services/core/java/com/android/server/pm/permission/BasePermission.java
+++ b/services/core/java/com/android/server/pm/permission/BasePermission.java
@@ -189,6 +189,11 @@
return (protectionLevel & PermissionInfo.PROTECTION_MASK_BASE)
== PermissionInfo.PROTECTION_DANGEROUS;
}
+
+ public boolean isRemoved() {
+ return perm.info != null && (perm.info.flags & PermissionInfo.FLAG_REMOVED) != 0;
+ }
+
public boolean isSignature() {
return (protectionLevel & PermissionInfo.PROTECTION_MASK_BASE) ==
PermissionInfo.PROTECTION_SIGNATURE;
@@ -235,6 +240,9 @@
return (protectionLevel & PermissionInfo.PROTECTION_FLAG_SYSTEM_TEXT_CLASSIFIER)
!= 0;
}
+ public boolean isWellbeing() {
+ return (protectionLevel & PermissionInfo.PROTECTION_FLAG_WELLBEING) != 0;
+ }
public void transfer(@NonNull String origPackageName, @NonNull String newPackageName) {
if (!origPackageName.equals(sourcePackageName)) {
diff --git a/services/core/java/com/android/server/pm/permission/PermissionManagerService.java b/services/core/java/com/android/server/pm/permission/PermissionManagerService.java
index 4406fdd..bc3c18d 100644
--- a/services/core/java/com/android/server/pm/permission/PermissionManagerService.java
+++ b/services/core/java/com/android/server/pm/permission/PermissionManagerService.java
@@ -799,6 +799,10 @@
continue;
}
+ if (bp.isRemoved()) {
+ continue;
+ }
+
// Limit ephemeral apps to ephemeral allowed permissions.
if (pkg.applicationInfo.isInstantApp() && !bp.isInstant()) {
if (DEBUG_PERMISSIONS) {
@@ -1637,6 +1641,12 @@
// Special permissions for the system default text classifier.
allowed = true;
}
+ if (!allowed && bp.isWellbeing()
+ && pkg.packageName.equals(mPackageManagerInt.getKnownPackageName(
+ PackageManagerInternal.PACKAGE_WELLBEING, UserHandle.USER_SYSTEM))) {
+ // Special permission granted only to the OEM specified wellbeing app
+ allowed = true;
+ }
}
return allowed;
}
diff --git a/services/core/java/com/android/server/role/RoleManagerService.java b/services/core/java/com/android/server/role/RoleManagerService.java
index 8ce3838..8711ddf 100644
--- a/services/core/java/com/android/server/role/RoleManagerService.java
+++ b/services/core/java/com/android/server/role/RoleManagerService.java
@@ -156,21 +156,16 @@
@MainThread
private void performInitialGrantsIfNecessary(@UserIdInt int userId) {
RoleUserState userState;
- synchronized (mLock) {
- userState = getUserStateLocked(userId);
- }
+ userState = getOrCreateUserState(userId);
String packagesHash = computeComponentStateHash(userId);
- String oldPackagesHash;
- synchronized (mLock) {
- oldPackagesHash = userState.getPackagesHashLocked();
- }
+ String oldPackagesHash = userState.getPackagesHash();
boolean needGrant = !Objects.equals(packagesHash, oldPackagesHash);
if (needGrant) {
// Some vital packages state has changed since last role grant
// Run grants again
Slog.i(LOG_TAG, "Granting default permissions...");
CompletableFuture<Void> result = new CompletableFuture<>();
- getControllerService(userId).onGrantDefaultRoles(
+ getOrCreateControllerService(userId).onGrantDefaultRoles(
new IRoleManagerCallback.Stub() {
@Override
public void onSuccess() {
@@ -183,9 +178,7 @@
});
try {
result.get(5, TimeUnit.SECONDS);
- synchronized (mLock) {
- userState.setPackagesHashLocked(packagesHash);
- }
+ userState.setPackagesHash(packagesHash);
} catch (InterruptedException | ExecutionException | TimeoutException e) {
Slog.e(LOG_TAG, "Failed to grant defaults for user " + userId, e);
}
@@ -225,35 +218,38 @@
return PackageUtils.computeSha256Digest(out.toByteArray());
}
- @GuardedBy("mLock")
@NonNull
- private RoleUserState getUserStateLocked(@UserIdInt int userId) {
- RoleUserState userState = mUserStates.get(userId);
- if (userState == null) {
- userState = RoleUserState.newInstanceLocked(userId);
- mUserStates.put(userId, userState);
+ private RoleUserState getOrCreateUserState(@UserIdInt int userId) {
+ synchronized (mLock) {
+ RoleUserState userState = mUserStates.get(userId);
+ if (userState == null) {
+ userState = new RoleUserState(userId);
+ mUserStates.put(userId, userState);
+ }
+ return userState;
}
- return userState;
}
- @GuardedBy("mLock")
@NonNull
- private RemoteRoleControllerService getControllerService(@UserIdInt int userId) {
- RemoteRoleControllerService controllerService = mControllerServices.get(userId);
- if (controllerService == null) {
- controllerService = new RemoteRoleControllerService(userId, getContext());
- mControllerServices.put(userId, controllerService);
+ private RemoteRoleControllerService getOrCreateControllerService(@UserIdInt int userId) {
+ synchronized (mLock) {
+ RemoteRoleControllerService controllerService = mControllerServices.get(userId);
+ if (controllerService == null) {
+ controllerService = new RemoteRoleControllerService(userId, getContext());
+ mControllerServices.put(userId, controllerService);
+ }
+ return controllerService;
}
- return controllerService;
}
private void onRemoveUser(@UserIdInt int userId) {
+ RoleUserState userState;
synchronized (mLock) {
mControllerServices.remove(userId);
- RoleUserState userState = mUserStates.removeReturnOld(userId);
- if (userState != null) {
- userState.destroyLocked();
- }
+ userState = mUserStates.removeReturnOld(userId);
+ }
+ if (userState != null) {
+ userState.destroy();
}
}
@@ -264,10 +260,8 @@
Preconditions.checkStringNotEmpty(roleName, "roleName cannot be null or empty");
int userId = UserHandle.getUserId(getCallingUid());
- synchronized (mLock) {
- RoleUserState userState = getUserStateLocked(userId);
- return userState.isRoleAvailableLocked(roleName);
- }
+ RoleUserState userState = getOrCreateUserState(userId);
+ return userState.isRoleAvailable(roleName);
}
@Override
@@ -307,10 +301,8 @@
@Nullable
private ArraySet<String> getRoleHoldersInternal(@NonNull String roleName,
@UserIdInt int userId) {
- synchronized (mLock) {
- RoleUserState userState = getUserStateLocked(userId);
- return userState.getRoleHoldersLocked(roleName);
- }
+ RoleUserState userState = getOrCreateUserState(userId);
+ return userState.getRoleHolders(roleName);
}
@Override
@@ -327,7 +319,7 @@
getContext().enforceCallingOrSelfPermission(Manifest.permission.MANAGE_ROLE_HOLDERS,
"addRoleHolderAsUser");
- getControllerService(userId).onAddRoleHolder(roleName, packageName, callback);
+ getOrCreateControllerService(userId).onAddRoleHolder(roleName, packageName, callback);
}
@Override
@@ -344,7 +336,7 @@
getContext().enforceCallingOrSelfPermission(Manifest.permission.MANAGE_ROLE_HOLDERS,
"removeRoleHolderAsUser");
- getControllerService(userId).onRemoveRoleHolder(roleName, packageName,
+ getOrCreateControllerService(userId).onRemoveRoleHolder(roleName, packageName,
callback);
}
@@ -361,7 +353,7 @@
getContext().enforceCallingOrSelfPermission(Manifest.permission.MANAGE_ROLE_HOLDERS,
"clearRoleHoldersAsUser");
- getControllerService(userId).onClearRoleHolders(roleName, callback);
+ getOrCreateControllerService(userId).onClearRoleHolders(roleName, callback);
}
@Override
@@ -372,10 +364,8 @@
"setRoleNamesFromController");
int userId = UserHandle.getCallingUserId();
- synchronized (mLock) {
- RoleUserState userState = getUserStateLocked(userId);
- userState.setRoleNamesLocked(roleNames);
- }
+ RoleUserState userState = getOrCreateUserState(userId);
+ userState.setRoleNames(roleNames);
}
@Override
@@ -388,10 +378,8 @@
"addRoleHolderFromController");
int userId = UserHandle.getCallingUserId();
- synchronized (mLock) {
- RoleUserState userState = getUserStateLocked(userId);
- return userState.addRoleHolderLocked(roleName, packageName);
- }
+ RoleUserState userState = getOrCreateUserState(userId);
+ return userState.addRoleHolder(roleName, packageName);
}
@Override
@@ -404,10 +392,8 @@
"removeRoleHolderFromController");
int userId = UserHandle.getCallingUserId();
- synchronized (mLock) {
- RoleUserState userState = getUserStateLocked(userId);
- return userState.removeRoleHolderLocked(roleName, packageName);
- }
+ RoleUserState userState = getOrCreateUserState(userId);
+ return userState.removeRoleHolder(roleName, packageName);
}
@CheckResult
@@ -440,16 +426,14 @@
dumpOutputStream = new DualDumpOutputStream(new IndentingPrintWriter(fout, " "));
}
- synchronized (mLock) {
- int[] userIds = mUserManagerInternal.getUserIds();
- int userIdsLength = userIds.length;
- for (int i = 0; i < userIdsLength; i++) {
- int userId = userIds[i];
+ int[] userIds = mUserManagerInternal.getUserIds();
+ int userIdsLength = userIds.length;
+ for (int i = 0; i < userIdsLength; i++) {
+ int userId = userIds[i];
- RoleUserState userState = getUserStateLocked(userId);
- userState.dumpLocked(dumpOutputStream, "user_states",
- RoleManagerServiceDumpProto.USER_STATES);
- }
+ RoleUserState userState = getOrCreateUserState(userId);
+ userState.dump(dumpOutputStream, "user_states",
+ RoleManagerServiceDumpProto.USER_STATES);
}
dumpOutputStream.flush();
diff --git a/services/core/java/com/android/server/role/RoleUserState.java b/services/core/java/com/android/server/role/RoleUserState.java
index 327debf..ec614a4 100644
--- a/services/core/java/com/android/server/role/RoleUserState.java
+++ b/services/core/java/com/android/server/role/RoleUserState.java
@@ -62,7 +62,6 @@
private static final String ROLES_FILE_NAME = "roles.xml";
private static final long WRITE_DELAY_MILLIS = 200;
- private static final long MAX_WRITE_DELAY_MILLIS = 2000;
private static final String TAG_ROLES = "roles";
private static final String TAG_ROLE = "role";
@@ -74,54 +73,51 @@
@UserIdInt
private final int mUserId;
- @GuardedBy("RoleManagerService.mLock")
+ @NonNull
+ private final Object mLock = new Object();
+
+ @GuardedBy("mLock")
private int mVersion = VERSION_UNDEFINED;
- @GuardedBy("RoleManagerService.mLock")
+ @GuardedBy("mLock")
@Nullable
private String mPackagesHash;
/**
* Maps role names to its holders' package names. The values should never be null.
*/
- @GuardedBy("RoleManagerService.mLock")
+ @GuardedBy("mLock")
@NonNull
private ArrayMap<String, ArraySet<String>> mRoles = new ArrayMap<>();
- @GuardedBy("RoleManagerService.mLock")
- private long mWritePendingSinceMillis;
+ @GuardedBy("mLock")
+ private boolean mWriteScheduled;
- @GuardedBy("RoleManagerService.mLock")
+ @GuardedBy("mLock")
private boolean mDestroyed;
@NonNull
private final Handler mWriteHandler = new Handler(BackgroundThread.getHandler().getLooper());
- private RoleUserState(@UserIdInt int userId) {
- mUserId = userId;
-
- readLocked();
- }
-
/**
* Create a new instance of user state, and read its state from disk if previously persisted.
*
* @param userId the user id for the new user state
- *
- * @return the new user state
*/
- @GuardedBy("RoleManagerService.mLock")
- public static RoleUserState newInstanceLocked(@UserIdInt int userId) {
- return new RoleUserState(userId);
+ public RoleUserState(@UserIdInt int userId) {
+ mUserId = userId;
+
+ readFile();
}
/**
* Get the version of this user state.
*/
- @GuardedBy("RoleManagerService.mLock")
- public int getVersionLocked() {
- throwIfDestroyedLocked();
- return mVersion;
+ public int getVersion() {
+ synchronized (mLock) {
+ throwIfDestroyedLocked();
+ return mVersion;
+ }
}
/**
@@ -129,14 +125,15 @@
*
* @param version the version to set
*/
- @GuardedBy("RoleManagerService.mLock")
- public void setVersionLocked(int version) {
- throwIfDestroyedLocked();
- if (mVersion == version) {
- return;
+ public void setVersion(int version) {
+ synchronized (mLock) {
+ throwIfDestroyedLocked();
+ if (mVersion == version) {
+ return;
+ }
+ mVersion = version;
+ scheduleWriteFileLocked();
}
- mVersion = version;
- writeAsyncLocked();
}
/**
@@ -144,9 +141,11 @@
*
* @return the hash representing the state of packages
*/
- @GuardedBy("RoleManagerService.mLock")
- public String getPackagesHashLocked() {
- return mPackagesHash;
+ @Nullable
+ public String getPackagesHash() {
+ synchronized (mLock) {
+ return mPackagesHash;
+ }
}
/**
@@ -154,14 +153,15 @@
*
* @param packagesHash the hash representing the state of packages
*/
- @GuardedBy("RoleManagerService.mLock")
- public void setPackagesHashLocked(@Nullable String packagesHash) {
- throwIfDestroyedLocked();
- if (Objects.equals(mPackagesHash, packagesHash)) {
- return;
+ public void setPackagesHash(@Nullable String packagesHash) {
+ synchronized (mLock) {
+ throwIfDestroyedLocked();
+ if (Objects.equals(mPackagesHash, packagesHash)) {
+ return;
+ }
+ mPackagesHash = packagesHash;
+ scheduleWriteFileLocked();
}
- mPackagesHash = packagesHash;
- writeAsyncLocked();
}
/**
@@ -171,10 +171,11 @@
*
* @return whether the role is available
*/
- @GuardedBy("RoleManagerService.mLock")
- public boolean isRoleAvailableLocked(@NonNull String roleName) {
- throwIfDestroyedLocked();
- return mRoles.containsKey(roleName);
+ public boolean isRoleAvailable(@NonNull String roleName) {
+ synchronized (mLock) {
+ throwIfDestroyedLocked();
+ return mRoles.containsKey(roleName);
+ }
}
/**
@@ -184,11 +185,12 @@
*
* @return the set of role holders. {@code null} should not be returned and indicates an issue.
*/
- @GuardedBy("RoleManagerService.mLock")
@Nullable
- public ArraySet<String> getRoleHoldersLocked(@NonNull String roleName) {
- throwIfDestroyedLocked();
- return mRoles.get(roleName);
+ public ArraySet<String> getRoleHolders(@NonNull String roleName) {
+ synchronized (mLock) {
+ throwIfDestroyedLocked();
+ return new ArraySet<>(mRoles.get(roleName));
+ }
}
/**
@@ -196,33 +198,35 @@
*
* @param roleNames the names of all the available roles
*/
- @GuardedBy("RoleManagerService.mLock")
- public void setRoleNamesLocked(@NonNull List<String> roleNames) {
- throwIfDestroyedLocked();
- boolean changed = false;
- for (int i = mRoles.size() - 1; i >= 0; i--) {
- String roleName = mRoles.keyAt(i);
- if (!roleNames.contains(roleName)) {
- ArraySet<String> packageNames = mRoles.valueAt(i);
- if (!packageNames.isEmpty()) {
- Slog.e(LOG_TAG, "Holders of a removed role should have been cleaned up, role: "
- + roleName + ", holders: " + packageNames);
+ public void setRoleNames(@NonNull List<String> roleNames) {
+ synchronized (mLock) {
+ throwIfDestroyedLocked();
+ boolean changed = false;
+ for (int i = mRoles.size() - 1; i >= 0; i--) {
+ String roleName = mRoles.keyAt(i);
+ if (!roleNames.contains(roleName)) {
+ ArraySet<String> packageNames = mRoles.valueAt(i);
+ if (!packageNames.isEmpty()) {
+ Slog.e(LOG_TAG,
+ "Holders of a removed role should have been cleaned up, role: "
+ + roleName + ", holders: " + packageNames);
+ }
+ mRoles.removeAt(i);
+ changed = true;
}
- mRoles.removeAt(i);
- changed = true;
}
- }
- int roleNamesSize = roleNames.size();
- for (int i = 0; i < roleNamesSize; i++) {
- String roleName = roleNames.get(i);
- if (!mRoles.containsKey(roleName)) {
- mRoles.put(roleName, new ArraySet<>());
- Slog.i(LOG_TAG, "Added new role: " + roleName);
- changed = true;
+ int roleNamesSize = roleNames.size();
+ for (int i = 0; i < roleNamesSize; i++) {
+ String roleName = roleNames.get(i);
+ if (!mRoles.containsKey(roleName)) {
+ mRoles.put(roleName, new ArraySet<>());
+ Slog.i(LOG_TAG, "Added new role: " + roleName);
+ changed = true;
+ }
}
- }
- if (changed) {
- writeAsyncLocked();
+ if (changed) {
+ scheduleWriteFileLocked();
+ }
}
}
@@ -236,20 +240,21 @@
* indicates an issue.
*/
@CheckResult
- @GuardedBy("RoleManagerService.mLock")
- public boolean addRoleHolderLocked(@NonNull String roleName, @NonNull String packageName) {
- throwIfDestroyedLocked();
- ArraySet<String> roleHolders = mRoles.get(roleName);
- if (roleHolders == null) {
- Slog.e(LOG_TAG, "Cannot add role holder for unknown role, role: " + roleName
- + ", package: " + packageName);
- return false;
+ public boolean addRoleHolder(@NonNull String roleName, @NonNull String packageName) {
+ synchronized (mLock) {
+ throwIfDestroyedLocked();
+ ArraySet<String> roleHolders = mRoles.get(roleName);
+ if (roleHolders == null) {
+ Slog.e(LOG_TAG, "Cannot add role holder for unknown role, role: " + roleName
+ + ", package: " + packageName);
+ return false;
+ }
+ boolean changed = roleHolders.add(packageName);
+ if (changed) {
+ scheduleWriteFileLocked();
+ }
+ return true;
}
- boolean changed = roleHolders.add(packageName);
- if (changed) {
- writeAsyncLocked();
- }
- return true;
}
/**
@@ -262,63 +267,54 @@
* indicates an issue.
*/
@CheckResult
- @GuardedBy("RoleManagerService.mLock")
- public boolean removeRoleHolderLocked(@NonNull String roleName, @NonNull String packageName) {
- throwIfDestroyedLocked();
- ArraySet<String> roleHolders = mRoles.get(roleName);
- if (roleHolders == null) {
- Slog.e(LOG_TAG, "Cannot remove role holder for unknown role, role: " + roleName
- + ", package: " + packageName);
- return false;
+ public boolean removeRoleHolder(@NonNull String roleName, @NonNull String packageName) {
+ synchronized (mLock) {
+ throwIfDestroyedLocked();
+ ArraySet<String> roleHolders = mRoles.get(roleName);
+ if (roleHolders == null) {
+ Slog.e(LOG_TAG, "Cannot remove role holder for unknown role, role: " + roleName
+ + ", package: " + packageName);
+ return false;
+ }
+ boolean changed = roleHolders.remove(packageName);
+ if (changed) {
+ scheduleWriteFileLocked();
+ }
+ return true;
}
- boolean changed = roleHolders.remove(packageName);
- if (changed) {
- writeAsyncLocked();
- }
- return true;
}
/**
* Schedule writing the state to file.
*/
- @GuardedBy("RoleManagerService.mLock")
- private void writeAsyncLocked() {
+ @GuardedBy("mLock")
+ private void scheduleWriteFileLocked() {
throwIfDestroyedLocked();
- ArrayMap<String, ArraySet<String>> roles = new ArrayMap<>();
- for (int i = 0, size = CollectionUtils.size(mRoles); i < size; ++i) {
- String roleName = mRoles.keyAt(i);
- ArraySet<String> roleHolders = mRoles.valueAt(i);
-
- roleHolders = new ArraySet<>(roleHolders);
- roles.put(roleName, roleHolders);
+ if (!mWriteScheduled) {
+ mWriteHandler.sendMessageDelayed(PooledLambda.obtainMessage(RoleUserState::writeFile,
+ this), WRITE_DELAY_MILLIS);
+ mWriteScheduled = true;
}
-
- long currentTimeMillis = System.currentTimeMillis();
- long writeDelayMillis;
- if (!mWriteHandler.hasMessagesOrCallbacks()) {
- mWritePendingSinceMillis = currentTimeMillis;
- writeDelayMillis = WRITE_DELAY_MILLIS;
- } else {
- mWriteHandler.removeCallbacksAndMessages(null);
- long writePendingDurationMillis = currentTimeMillis - mWritePendingSinceMillis;
- if (writePendingDurationMillis >= MAX_WRITE_DELAY_MILLIS) {
- writeDelayMillis = 0;
- } else {
- long maxWriteDelayMillis = Math.max(MAX_WRITE_DELAY_MILLIS
- - writePendingDurationMillis, 0);
- writeDelayMillis = Math.min(WRITE_DELAY_MILLIS, maxWriteDelayMillis);
- }
- }
-
- mWriteHandler.sendMessageDelayed(PooledLambda.obtainMessage(RoleUserState::writeSync, this,
- mVersion, mPackagesHash, roles), writeDelayMillis);
- Slog.i(LOG_TAG, "Scheduled writing roles.xml");
}
@WorkerThread
- private void writeSync(int version, @Nullable String packagesHash,
- @NonNull ArrayMap<String, ArraySet<String>> roles) {
+ private void writeFile() {
+ int version;
+ String packagesHash;
+ ArrayMap<String, ArraySet<String>> roles;
+ synchronized (mLock) {
+ if (mDestroyed) {
+ return;
+ }
+
+ mWriteScheduled = false;
+
+ version = mVersion;
+ packagesHash = mPackagesHash;
+ roles = snapshotRolesLocked();
+ }
+
AtomicFile atomicFile = new AtomicFile(getFile(mUserId), "roles-" + mUserId);
FileOutputStream out = null;
try {
@@ -385,18 +381,19 @@
/**
* Read the state from file.
*/
- @GuardedBy("RoleManagerService.mLock")
- private void readLocked() {
- File file = getFile(mUserId);
- try (FileInputStream in = new AtomicFile(file).openRead()) {
- XmlPullParser parser = Xml.newPullParser();
- parser.setInput(in, null);
- parseXmlLocked(parser);
- Slog.i(LOG_TAG, "Read roles.xml successfully");
- } catch (FileNotFoundException e) {
- Slog.i(LOG_TAG, "roles.xml not found");
- } catch (XmlPullParserException | IOException e) {
- throw new IllegalStateException("Failed to parse roles.xml: " + file, e);
+ private void readFile() {
+ synchronized (mLock) {
+ File file = getFile(mUserId);
+ try (FileInputStream in = new AtomicFile(file).openRead()) {
+ XmlPullParser parser = Xml.newPullParser();
+ parser.setInput(in, null);
+ parseXmlLocked(parser);
+ Slog.i(LOG_TAG, "Read roles.xml successfully");
+ } catch (FileNotFoundException e) {
+ Slog.i(LOG_TAG, "roles.xml not found");
+ } catch (XmlPullParserException | IOException e) {
+ throw new IllegalStateException("Failed to parse roles.xml: " + file, e);
+ }
}
}
@@ -470,20 +467,28 @@
*
* @param dumpOutputStream the output stream to dump to
*/
- @GuardedBy("RoleManagerService.mLock")
- public void dumpLocked(@NonNull DualDumpOutputStream dumpOutputStream,
- @NonNull String fieldName, long fieldId) {
- throwIfDestroyedLocked();
+ public void dump(@NonNull DualDumpOutputStream dumpOutputStream, @NonNull String fieldName,
+ long fieldId) {
+ int version;
+ String packagesHash;
+ ArrayMap<String, ArraySet<String>> roles;
+ synchronized (mLock) {
+ throwIfDestroyedLocked();
+
+ version = mVersion;
+ packagesHash = mPackagesHash;
+ roles = snapshotRolesLocked();
+ }
long fieldToken = dumpOutputStream.start(fieldName, fieldId);
dumpOutputStream.write("user_id", RoleUserStateProto.USER_ID, mUserId);
- dumpOutputStream.write("version", RoleUserStateProto.VERSION, mVersion);
- dumpOutputStream.write("packages_hash", RoleUserStateProto.PACKAGES_HASH, mPackagesHash);
+ dumpOutputStream.write("version", RoleUserStateProto.VERSION, version);
+ dumpOutputStream.write("packages_hash", RoleUserStateProto.PACKAGES_HASH, packagesHash);
- int rolesSize = mRoles.size();
+ int rolesSize = roles.size();
for (int rolesIndex = 0; rolesIndex < rolesSize; rolesIndex++) {
- String roleName = mRoles.keyAt(rolesIndex);
- ArraySet<String> roleHolders = mRoles.valueAt(rolesIndex);
+ String roleName = roles.keyAt(rolesIndex);
+ ArraySet<String> roleHolders = roles.valueAt(rolesIndex);
long rolesToken = dumpOutputStream.start("roles", RoleUserStateProto.ROLES);
dumpOutputStream.write("name", RoleProto.NAME, roleName);
@@ -501,19 +506,33 @@
dumpOutputStream.end(fieldToken);
}
+ @GuardedBy("mLock")
+ private ArrayMap<String, ArraySet<String>> snapshotRolesLocked() {
+ ArrayMap<String, ArraySet<String>> roles = new ArrayMap<>();
+ for (int i = 0, size = CollectionUtils.size(mRoles); i < size; ++i) {
+ String roleName = mRoles.keyAt(i);
+ ArraySet<String> roleHolders = mRoles.valueAt(i);
+
+ roleHolders = new ArraySet<>(roleHolders);
+ roles.put(roleName, roleHolders);
+ }
+ return roles;
+ }
+
/**
* Destroy this state and delete the corresponding file. Any pending writes to the file will be
* cancelled and any future interaction with this state will throw an exception.
*/
- @GuardedBy("RoleManagerService.mLock")
- public void destroyLocked() {
- throwIfDestroyedLocked();
- mWriteHandler.removeCallbacksAndMessages(null);
- getFile(mUserId).delete();
- mDestroyed = true;
+ public void destroy() {
+ synchronized (mLock) {
+ throwIfDestroyedLocked();
+ mWriteHandler.removeCallbacksAndMessages(null);
+ getFile(mUserId).delete();
+ mDestroyed = true;
+ }
}
- @GuardedBy("RoleManagerService.mLock")
+ @GuardedBy("mLock")
private void throwIfDestroyedLocked() {
if (mDestroyed) {
throw new IllegalStateException("This RoleUserState has already been destroyed");
diff --git a/services/core/java/com/android/server/signedconfig/InvalidConfigException.java b/services/core/java/com/android/server/signedconfig/InvalidConfigException.java
new file mode 100644
index 0000000..f01baa4
--- /dev/null
+++ b/services/core/java/com/android/server/signedconfig/InvalidConfigException.java
@@ -0,0 +1,33 @@
+/*
+ * 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.server.signedconfig;
+
+/**
+ * Thrown when there is a problem parsing the config embedded in an APK.
+ */
+public class InvalidConfigException extends Exception {
+
+ public InvalidConfigException(String message) {
+ super(message);
+ }
+
+ public InvalidConfigException(String message, Exception cause) {
+ super(message, cause);
+ }
+
+
+}
diff --git a/services/core/java/com/android/server/signedconfig/SignedConfig.java b/services/core/java/com/android/server/signedconfig/SignedConfig.java
new file mode 100644
index 0000000..a3f452c
--- /dev/null
+++ b/services/core/java/com/android/server/signedconfig/SignedConfig.java
@@ -0,0 +1,137 @@
+/*
+ * 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.server.signedconfig;
+
+import com.android.internal.annotations.VisibleForTesting;
+
+import org.json.JSONArray;
+import org.json.JSONException;
+import org.json.JSONObject;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
+/**
+ * Represents signed configuration.
+ *
+ * <p>This configuration should only be used if the signature has already been verified.
+ */
+public class SignedConfig {
+
+ private static final String KEY_VERSION = "version";
+ private static final String KEY_CONFIG = "config";
+
+ private static final String CONFIG_KEY_MIN_SDK = "minSdk";
+ private static final String CONFIG_KEY_MAX_SDK = "maxSdk";
+ private static final String CONFIG_KEY_VALUES = "values";
+ // TODO it may be better to use regular key/value pairs in a JSON object, rather than an array
+ // of objects with the 2 keys below.
+ private static final String CONFIG_KEY_KEY = "key";
+ private static final String CONFIG_KEY_VALUE = "value";
+
+ /**
+ * Represents config values targetting to an SDK range.
+ */
+ public static class PerSdkConfig {
+ public final int minSdk;
+ public final int maxSdk;
+ public final Map<String, String> values;
+
+ public PerSdkConfig(int minSdk, int maxSdk, Map<String, String> values) {
+ this.minSdk = minSdk;
+ this.maxSdk = maxSdk;
+ this.values = Collections.unmodifiableMap(values);
+ }
+
+ }
+
+ public final int version;
+ public final List<PerSdkConfig> perSdkConfig;
+
+ public SignedConfig(int version, List<PerSdkConfig> perSdkConfig) {
+ this.version = version;
+ this.perSdkConfig = Collections.unmodifiableList(perSdkConfig);
+ }
+
+ /**
+ * Find matching sdk config for a given SDK level.
+ *
+ * @param sdkVersion SDK version of device.
+ * @return Matching config, of {@code null} if there is none.
+ */
+ public PerSdkConfig getMatchingConfig(int sdkVersion) {
+ for (PerSdkConfig config : perSdkConfig) {
+ if (config.minSdk <= sdkVersion && sdkVersion <= config.maxSdk) {
+ return config;
+ }
+ }
+ // nothing matching
+ return null;
+ }
+
+ /**
+ * Parse configuration from an APK.
+ *
+ * @param config config as read from the APK metadata.
+ * @return Parsed configuration.
+ * @throws InvalidConfigException If there's a problem parsing the config.
+ */
+ public static SignedConfig parse(String config, Set<String> allowedKeys)
+ throws InvalidConfigException {
+ try {
+ JSONObject json = new JSONObject(config);
+ int version = json.getInt(KEY_VERSION);
+
+ JSONArray perSdkConfig = json.getJSONArray(KEY_CONFIG);
+ List<PerSdkConfig> parsedConfigs = new ArrayList<>();
+ for (int i = 0; i < perSdkConfig.length(); ++i) {
+ parsedConfigs.add(parsePerSdkConfig(perSdkConfig.getJSONObject(i), allowedKeys));
+ }
+
+ return new SignedConfig(version, parsedConfigs);
+ } catch (JSONException e) {
+ throw new InvalidConfigException("Could not parse JSON", e);
+ }
+
+ }
+
+ @VisibleForTesting
+ static PerSdkConfig parsePerSdkConfig(JSONObject json, Set<String> allowedKeys)
+ throws JSONException, InvalidConfigException {
+ int minSdk = json.getInt(CONFIG_KEY_MIN_SDK);
+ int maxSdk = json.getInt(CONFIG_KEY_MAX_SDK);
+ JSONArray valueArray = json.getJSONArray(CONFIG_KEY_VALUES);
+ Map<String, String> values = new HashMap<>();
+ for (int i = 0; i < valueArray.length(); ++i) {
+ JSONObject keyValuePair = valueArray.getJSONObject(i);
+ String key = keyValuePair.getString(CONFIG_KEY_KEY);
+ String value = keyValuePair.has(CONFIG_KEY_VALUE)
+ ? keyValuePair.getString(CONFIG_KEY_VALUE)
+ : null;
+ if (!allowedKeys.contains(key)) {
+ throw new InvalidConfigException("Config key " + key + " is not allowed");
+ }
+ values.put(key, value);
+ }
+ return new PerSdkConfig(minSdk, maxSdk, values);
+ }
+
+}
diff --git a/services/core/java/com/android/server/textclassifier/TextClassificationManagerService.java b/services/core/java/com/android/server/textclassifier/TextClassificationManagerService.java
index c8a68b4..6b0419e 100644
--- a/services/core/java/com/android/server/textclassifier/TextClassificationManagerService.java
+++ b/services/core/java/com/android/server/textclassifier/TextClassificationManagerService.java
@@ -23,7 +23,6 @@
import android.content.Context;
import android.content.Intent;
import android.content.ServiceConnection;
-import android.content.pm.PackageManager;
import android.os.Binder;
import android.os.IBinder;
import android.os.RemoteException;
@@ -136,6 +135,7 @@
throws RemoteException {
Preconditions.checkNotNull(request);
Preconditions.checkNotNull(callback);
+ validateInput(mContext, request.getCallingPackageName());
synchronized (mLock) {
UserState userState = getCallingUserStateLocked();
@@ -158,6 +158,7 @@
throws RemoteException {
Preconditions.checkNotNull(request);
Preconditions.checkNotNull(callback);
+ validateInput(mContext, request.getCallingPackageName());
synchronized (mLock) {
UserState userState = getCallingUserStateLocked();
@@ -180,6 +181,7 @@
throws RemoteException {
Preconditions.checkNotNull(request);
Preconditions.checkNotNull(callback);
+ validateInput(mContext, request.getCallingPackageName());
synchronized (mLock) {
UserState userState = getCallingUserStateLocked();
@@ -199,7 +201,7 @@
public void onSelectionEvent(
TextClassificationSessionId sessionId, SelectionEvent event) throws RemoteException {
Preconditions.checkNotNull(event);
- validateInput(event.getPackageName(), mContext);
+ validateInput(mContext, event.getPackageName());
synchronized (mLock) {
UserState userState = getCallingUserStateLocked();
@@ -220,6 +222,7 @@
ITextLanguageCallback callback) throws RemoteException {
Preconditions.checkNotNull(request);
Preconditions.checkNotNull(callback);
+ validateInput(mContext, request.getCallingPackageName());
synchronized (mLock) {
UserState userState = getCallingUserStateLocked();
@@ -242,6 +245,7 @@
IConversationActionsCallback callback) throws RemoteException {
Preconditions.checkNotNull(request);
Preconditions.checkNotNull(callback);
+ validateInput(mContext, request.getCallingPackageName());
synchronized (mLock) {
UserState userState = getCallingUserStateLocked();
@@ -263,7 +267,7 @@
throws RemoteException {
Preconditions.checkNotNull(sessionId);
Preconditions.checkNotNull(classificationContext);
- validateInput(classificationContext.getPackageName(), mContext);
+ validateInput(mContext, classificationContext.getPackageName());
synchronized (mLock) {
UserState userState = getCallingUserStateLocked();
@@ -398,15 +402,17 @@
e -> Slog.d(LOG_TAG, "Error " + opDesc + ": " + e.getMessage()));
}
- private static void validateInput(String packageName, Context context)
+ private static void validateInput(Context context, @Nullable String packageName)
throws RemoteException {
+ if (packageName == null) return;
+
try {
final int uid = context.getPackageManager()
.getPackageUidAsUser(packageName, UserHandle.getCallingUserId());
Preconditions.checkArgument(Binder.getCallingUid() == uid);
- } catch (IllegalArgumentException | NullPointerException |
- PackageManager.NameNotFoundException e) {
- throw new RemoteException(e.getMessage());
+ } catch (Exception e) {
+ throw new RemoteException(
+ String.format("Invalid package: name=%s, error=%s", packageName, e));
}
}
diff --git a/services/core/java/com/android/server/wm/ActivityDisplay.java b/services/core/java/com/android/server/wm/ActivityDisplay.java
index da997ba..10542d5 100644
--- a/services/core/java/com/android/server/wm/ActivityDisplay.java
+++ b/services/core/java/com/android/server/wm/ActivityDisplay.java
@@ -48,12 +48,16 @@
import static com.android.server.wm.ActivityTaskManagerDebugConfig.TAG_WITH_CLASS_NAME;
import static com.android.server.wm.RootActivityContainer.FindTaskResult;
import static com.android.server.wm.RootActivityContainer.TAG_STATES;
+import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_FOCUS_LIGHT;
+import static com.android.server.wm.WindowManagerDebugConfig.TAG_WM;
+import static com.android.server.wm.WindowManagerService.UPDATE_FOCUS_NORMAL;
import android.annotation.Nullable;
import android.app.ActivityOptions;
import android.app.WindowConfiguration;
import android.content.res.Configuration;
import android.graphics.Point;
+import android.os.IBinder;
import android.os.UserHandle;
import android.util.IntArray;
import android.util.Slog;
@@ -86,6 +90,8 @@
private ActivityTaskManagerService mService;
private RootActivityContainer mRootActivityContainer;
+ // TODO: Remove once unification is complete.
+ DisplayContent mDisplayContent;
/** Actual Display this object tracks. */
int mDisplayId;
Display mDisplay;
@@ -138,8 +144,6 @@
// Used in updating the display size
private Point mTmpDisplaySize = new Point();
- private DisplayWindowController mWindowContainerController;
-
private final FindTaskResult mTmpFindTaskResult = new FindTaskResult();
ActivityDisplay(RootActivityContainer root, Display display) {
@@ -147,19 +151,15 @@
mService = root.mService;
mDisplayId = display.getDisplayId();
mDisplay = display;
- mWindowContainerController = createWindowContainerController();
+ mDisplayContent = createDisplayContent();
updateBounds();
}
- protected DisplayWindowController createWindowContainerController() {
- return new DisplayWindowController(mDisplay, this);
+ protected DisplayContent createDisplayContent() {
+ return mService.mWindowManager.mRoot.createDisplayContent(mDisplay, this);
}
- DisplayWindowController getWindowContainerController() {
- return mWindowContainerController;
- }
-
- void updateBounds() {
+ private void updateBounds() {
mDisplay.getRealSize(mTmpDisplaySize);
setBounds(0, 0, mTmpDisplaySize.x, mTmpDisplaySize.y);
}
@@ -178,7 +178,10 @@
}
updateBounds();
- mWindowContainerController.onDisplayChanged();
+ if (mDisplayContent != null) {
+ mDisplayContent.updateDisplayInfo();
+ mService.mWindowManager.requestTraversal();
+ }
}
@Override
@@ -270,9 +273,9 @@
// ActivityStack#getWindowContainerController() can be null. In this special case,
// since DisplayContest#positionStackAt() is called in TaskStack#onConfigurationChanged(),
// we don't have to call WindowContainerController#positionChildAt() here.
- if (stack.getWindowContainerController() != null) {
- mWindowContainerController.positionChildAt(stack.getWindowContainerController(),
- insertPosition, includingParents);
+ if (stack.getWindowContainerController() != null && mDisplayContent != null) {
+ mDisplayContent.positionStackAt(insertPosition,
+ stack.getWindowContainerController().mContainer, includingParents);
}
if (!wasContained) {
stack.setParent(this);
@@ -958,17 +961,23 @@
getRequestedOverrideConfiguration().windowConfiguration.getRotation();
if (currRotation != ROTATION_UNDEFINED
&& currRotation != overrideConfiguration.windowConfiguration.getRotation()
- && getWindowContainerController() != null) {
- getWindowContainerController().applyRotation(currRotation,
+ && mDisplayContent != null) {
+ mDisplayContent.applyRotationLocked(currRotation,
overrideConfiguration.windowConfiguration.getRotation());
}
super.onRequestedOverrideConfigurationChanged(overrideConfiguration);
+ if (mDisplayContent != null) {
+ mService.mWindowManager.setNewDisplayOverrideConfiguration(
+ overrideConfiguration, mDisplayContent);
+ }
}
@Override
public void onConfigurationChanged(Configuration newParentConfig) {
// update resources before cascade so that docked/pinned stacks use the correct info
- getWindowContainerController().preOnConfigurationChanged();
+ if (mDisplayContent != null) {
+ mDisplayContent.preOnConfigurationChanged();
+ }
super.onConfigurationChanged(newParentConfig);
}
@@ -1099,8 +1108,8 @@
private void releaseSelfIfNeeded() {
if (mStacks.isEmpty() && mRemoved) {
- mWindowContainerController.removeContainer();
- mWindowContainerController = null;
+ mDisplayContent.removeIfPossible();
+ mDisplayContent = null;
mRootActivityContainer.removeChild(this);
mRootActivityContainer.mStackSupervisor
.getKeyguardController().onDisplayRemoved(mDisplayId);
@@ -1122,7 +1131,7 @@
* @see Display#FLAG_SHOULD_SHOW_SYSTEM_DECORATIONS
*/
boolean supportsSystemDecorations() {
- return mWindowContainerController.supportsSystemDecorations();
+ return mDisplayContent.supportsSystemDecorations();
}
@VisibleForTesting
@@ -1136,7 +1145,30 @@
}
void setFocusedApp(ActivityRecord r, boolean moveFocusNow) {
- mWindowContainerController.setFocusedApp(r.appToken, moveFocusNow);
+ if (mDisplayContent == null) {
+ return;
+ }
+ final AppWindowToken newFocus;
+ final IBinder token = r.appToken;
+ if (token == null) {
+ if (DEBUG_FOCUS_LIGHT) Slog.v(TAG_WM, "Clearing focused app, displayId="
+ + mDisplayId);
+ newFocus = null;
+ } else {
+ newFocus = mService.mWindowManager.mRoot.getAppWindowToken(token);
+ if (newFocus == null) {
+ Slog.w(TAG_WM, "Attempted to set focus to non-existing app token: " + token
+ + ", displayId=" + mDisplayId);
+ }
+ if (DEBUG_FOCUS_LIGHT) Slog.v(TAG_WM, "Set focused app to: " + newFocus
+ + " moveFocusNow=" + moveFocusNow + " displayId=" + mDisplayId);
+ }
+
+ final boolean changed = mDisplayContent.setFocusedApp(newFocus);
+ if (moveFocusNow && changed) {
+ mService.mWindowManager.updateFocusedWindowLocked(UPDATE_FOCUS_NORMAL,
+ true /*updateInputWindows*/);
+ }
}
/**
@@ -1284,17 +1316,21 @@
}
/**
- * See {@link DisplayWindowController#deferUpdateImeTarget()}
+ * See {@link DisplayContent#deferUpdateImeTarget()}
*/
public void deferUpdateImeTarget() {
- mWindowContainerController.deferUpdateImeTarget();
+ if (mDisplayContent != null) {
+ mDisplayContent.deferUpdateImeTarget();
+ }
}
/**
- * See {@link DisplayWindowController#deferUpdateImeTarget()}
+ * See {@link DisplayContent#deferUpdateImeTarget()}
*/
public void continueUpdateImeTarget() {
- mWindowContainerController.continueUpdateImeTarget();
+ if (mDisplayContent != null) {
+ mDisplayContent.continueUpdateImeTarget();
+ }
}
public void dump(PrintWriter pw, String prefix) {
diff --git a/services/core/java/com/android/server/wm/ActivityRecord.java b/services/core/java/com/android/server/wm/ActivityRecord.java
index 26a4cef..4e9c5ab 100644
--- a/services/core/java/com/android/server/wm/ActivityRecord.java
+++ b/services/core/java/com/android/server/wm/ActivityRecord.java
@@ -2942,7 +2942,7 @@
final ActivityLifecycleItem lifecycleItem;
if (andResume) {
lifecycleItem = ResumeActivityItem.obtain(
- getDisplay().getWindowContainerController().isNextTransitionForward());
+ getDisplay().mDisplayContent.isNextTransitionForward());
} else {
lifecycleItem = PauseActivityItem.obtain();
}
diff --git a/services/core/java/com/android/server/wm/ActivityStack.java b/services/core/java/com/android/server/wm/ActivityStack.java
index c41a173..7683172 100644
--- a/services/core/java/com/android/server/wm/ActivityStack.java
+++ b/services/core/java/com/android/server/wm/ActivityStack.java
@@ -574,7 +574,7 @@
// bounds were on the pre-rotated display.
if (prevRotation != newRotation) {
mTmpRect2.set(mTmpRect);
- getDisplay().getWindowContainerController().mContainer
+ getDisplay().mDisplayContent
.rotateBounds(newParentConfig.windowConfiguration.getBounds(),
prevRotation, newRotation, mTmpRect2);
hasNewOverrideBounds = true;
@@ -609,8 +609,8 @@
} else if (
getRequestedOverrideWindowingMode() == WINDOWING_MODE_SPLIT_SCREEN_SECONDARY) {
Rect dockedBounds = display.getSplitScreenPrimaryStack().getBounds();
- final boolean isMinimizedDock = getDisplay().getWindowContainerController()
- .mContainer.getDockedDividerController().isMinimizedDock();
+ final boolean isMinimizedDock =
+ getDisplay().mDisplayContent.getDockedDividerController().isMinimizedDock();
if (isMinimizedDock) {
TaskRecord topTask = display.getSplitScreenPrimaryStack().topTask();
if (topTask != null) {
@@ -2714,16 +2714,16 @@
// that the previous one will be hidden soon. This way it can know
// to ignore it when computing the desired screen orientation.
boolean anim = true;
- final DisplayWindowController dwc = getDisplay().getWindowContainerController();
+ final DisplayContent dc = getDisplay().mDisplayContent;
if (prev != null) {
if (prev.finishing) {
if (DEBUG_TRANSITION) Slog.v(TAG_TRANSITION,
"Prepare close transition: prev=" + prev);
if (mStackSupervisor.mNoAnimActivities.contains(prev)) {
anim = false;
- dwc.prepareAppTransition(TRANSIT_NONE, false);
+ dc.prepareAppTransition(TRANSIT_NONE, false);
} else {
- dwc.prepareAppTransition(
+ dc.prepareAppTransition(
prev.getTaskRecord() == next.getTaskRecord() ? TRANSIT_ACTIVITY_CLOSE
: TRANSIT_TASK_CLOSE, false);
}
@@ -2733,9 +2733,9 @@
"Prepare open transition: prev=" + prev);
if (mStackSupervisor.mNoAnimActivities.contains(next)) {
anim = false;
- dwc.prepareAppTransition(TRANSIT_NONE, false);
+ dc.prepareAppTransition(TRANSIT_NONE, false);
} else {
- dwc.prepareAppTransition(
+ dc.prepareAppTransition(
prev.getTaskRecord() == next.getTaskRecord() ? TRANSIT_ACTIVITY_OPEN
: next.mLaunchTaskBehind ? TRANSIT_TASK_OPEN_BEHIND
: TRANSIT_TASK_OPEN, false);
@@ -2745,9 +2745,9 @@
if (DEBUG_TRANSITION) Slog.v(TAG_TRANSITION, "Prepare open transition: no previous");
if (mStackSupervisor.mNoAnimActivities.contains(next)) {
anim = false;
- dwc.prepareAppTransition(TRANSIT_NONE, false);
+ dc.prepareAppTransition(TRANSIT_NONE, false);
} else {
- dwc.prepareAppTransition(TRANSIT_ACTIVITY_OPEN, false);
+ dc.prepareAppTransition(TRANSIT_ACTIVITY_OPEN, false);
}
}
@@ -2869,8 +2869,7 @@
next.clearOptionsLocked();
transaction.setLifecycleStateRequest(
ResumeActivityItem.obtain(next.app.getReportedProcState(),
- getDisplay().getWindowContainerController()
- .isNextTransitionForward()));
+ getDisplay().mDisplayContent.isNextTransitionForward()));
mService.getLifecycleManager().scheduleTransaction(transaction);
if (DEBUG_STATES) Slog.d(TAG_STATES, "resumeTopActivityLocked: Resumed "
@@ -3072,11 +3071,11 @@
task.setFrontOfTask();
if (!isHomeOrRecentsStack() || numActivities() > 0) {
- final DisplayWindowController dwc = getDisplay().getWindowContainerController();
+ final DisplayContent dc = getDisplay().mDisplayContent;
if (DEBUG_TRANSITION) Slog.v(TAG_TRANSITION,
"Prepare open transition: starting " + r);
if ((r.intent.getFlags() & Intent.FLAG_ACTIVITY_NO_ANIMATION) != 0) {
- dwc.prepareAppTransition(TRANSIT_NONE, keepCurTransition);
+ dc.prepareAppTransition(TRANSIT_NONE, keepCurTransition);
mStackSupervisor.mNoAnimActivities.add(r);
} else {
int transit = TRANSIT_ACTIVITY_OPEN;
@@ -3095,7 +3094,7 @@
transit = TRANSIT_TASK_OPEN;
}
}
- dwc.prepareAppTransition(transit, keepCurTransition);
+ dc.prepareAppTransition(transit, keepCurTransition);
mStackSupervisor.mNoAnimActivities.remove(r);
}
boolean doShow = true;
@@ -3724,7 +3723,7 @@
int taskNdx = mTaskHistory.indexOf(finishedTask);
final TaskRecord task = finishedTask;
int activityNdx = task.mActivities.indexOf(r);
- getDisplay().getWindowContainerController().prepareAppTransition(
+ getDisplay().mDisplayContent.prepareAppTransition(
TRANSIT_CRASHING_ACTIVITY_CLOSE, false /* alwaysKeepCurrent */);
finishActivityLocked(r, Activity.RESULT_CANCELED, null, reason, false);
finishedTask = task;
@@ -3890,7 +3889,7 @@
mService.getTaskChangeNotificationController().notifyTaskRemovalStarted(
task.taskId);
}
- getDisplay().getWindowContainerController().prepareAppTransition(transit, false);
+ getDisplay().mDisplayContent.prepareAppTransition(transit, false);
// Tell window manager to prepare for this one to be removed.
r.setVisibility(false);
@@ -3945,10 +3944,10 @@
}
private void prepareActivityHideTransitionAnimation(ActivityRecord r, int transit) {
- final DisplayWindowController dwc = getDisplay().getWindowContainerController();
- dwc.prepareAppTransition(transit, false);
+ final DisplayContent dc = getDisplay().mDisplayContent;
+ dc.prepareAppTransition(transit, false);
r.setVisibility(false);
- dwc.executeAppTransition();
+ dc.executeAppTransition();
if (!mStackSupervisor.mActivitiesWaitingForVisibleActivity.contains(r)) {
mStackSupervisor.mActivitiesWaitingForVisibleActivity.add(r);
}
@@ -4692,7 +4691,7 @@
ActivityOptions.abort(options);
}
}
- getDisplay().getWindowContainerController().prepareAppTransition(transit, false);
+ getDisplay().mDisplayContent.prepareAppTransition(transit, false);
}
private void updateTaskMovement(TaskRecord task, boolean toFront) {
@@ -4761,8 +4760,7 @@
if (DEBUG_TRANSITION) Slog.v(TAG_TRANSITION, "Prepare to front transition: task=" + tr);
if (noAnimation) {
- getDisplay().getWindowContainerController().prepareAppTransition(
- TRANSIT_NONE, false);
+ getDisplay().mDisplayContent.prepareAppTransition(TRANSIT_NONE, false);
if (r != null) {
mStackSupervisor.mNoAnimActivities.add(r);
}
@@ -4844,8 +4842,7 @@
mTaskHistory.add(0, tr);
updateTaskMovement(tr, false);
- getDisplay().getWindowContainerController().prepareAppTransition(
- TRANSIT_TASK_TO_BACK, false);
+ getDisplay().mDisplayContent.prepareAppTransition(TRANSIT_TASK_TO_BACK, false);
moveToBack("moveTaskToBackLocked", tr);
if (inPinnedWindowingMode()) {
@@ -5170,7 +5167,7 @@
+ r.intent.getComponent().flattenToShortString());
// Force the destroy to skip right to removal.
r.app = null;
- getDisplay().getWindowContainerController().prepareAppTransition(
+ getDisplay().mDisplayContent.prepareAppTransition(
TRANSIT_CRASHING_ACTIVITY_CLOSE, false /* alwaysKeepCurrent */);
finishCurrentActivityLocked(r, FINISH_IMMEDIATELY, false,
"handleAppCrashedLocked");
@@ -5508,7 +5505,7 @@
}
void executeAppTransition(ActivityOptions options) {
- getDisplay().getWindowContainerController().executeAppTransition();
+ getDisplay().mDisplayContent.executeAppTransition();
ActivityOptions.abort(options);
}
diff --git a/services/core/java/com/android/server/wm/ActivityStackSupervisor.java b/services/core/java/com/android/server/wm/ActivityStackSupervisor.java
index d92a9f2..e761ad8 100644
--- a/services/core/java/com/android/server/wm/ActivityStackSupervisor.java
+++ b/services/core/java/com/android/server/wm/ActivityStackSupervisor.java
@@ -818,7 +818,7 @@
final ClientTransaction clientTransaction = ClientTransaction.obtain(
proc.getThread(), r.appToken);
- final DisplayWindowController dwc = r.getDisplay().getWindowContainerController();
+ final DisplayContent dc = r.getDisplay().mDisplayContent;
clientTransaction.addCallback(LaunchActivityItem.obtain(new Intent(r.intent),
System.identityHashCode(r), r.info,
// TODO: Have this take the merged configuration instead of separate global
@@ -827,12 +827,12 @@
mergedConfiguration.getOverrideConfiguration(), r.compat,
r.launchedFromPackage, task.voiceInteractor, proc.getReportedProcState(),
r.icicle, r.persistentState, results, newIntents,
- dwc.isNextTransitionForward(), profilerInfo));
+ dc.isNextTransitionForward(), profilerInfo));
// Set desired final state.
final ActivityLifecycleItem lifecycleItem;
if (andResume) {
- lifecycleItem = ResumeActivityItem.obtain(dwc.isNextTransitionForward());
+ lifecycleItem = ResumeActivityItem.obtain(dc.isNextTransitionForward());
} else {
lifecycleItem = PauseActivityItem.obtain();
}
diff --git a/services/core/java/com/android/server/wm/ActivityStarter.java b/services/core/java/com/android/server/wm/ActivityStarter.java
index bc2136e..57bfc29 100644
--- a/services/core/java/com/android/server/wm/ActivityStarter.java
+++ b/services/core/java/com/android/server/wm/ActivityStarter.java
@@ -1565,7 +1565,7 @@
mTargetStack.ensureActivitiesVisibleLocked(null, 0, !PRESERVE_WINDOWS);
// Go ahead and tell window manager to execute app transition for this activity
// since the app transition will not be triggered through the resume channel.
- mTargetStack.getDisplay().getWindowContainerController().executeAppTransition();
+ mTargetStack.getDisplay().mDisplayContent.executeAppTransition();
} else {
// If the target stack was not previously focusable (previous top running activity
// on that stack was not visible) then any prior calls to move the stack to the
@@ -2506,8 +2506,9 @@
// full resolution.
mLaunchParams.mPreferredDisplayId =
mPreferredDisplayId != DEFAULT_DISPLAY ? mPreferredDisplayId : INVALID_DISPLAY;
+ final boolean onTop = aOptions == null || !aOptions.getAvoidMoveToFront();
final ActivityStack stack =
- mRootActivityContainer.getLaunchStack(r, aOptions, task, ON_TOP, mLaunchParams);
+ mRootActivityContainer.getLaunchStack(r, aOptions, task, onTop, mLaunchParams);
mLaunchParams.mPreferredDisplayId = mPreferredDisplayId;
return stack;
}
diff --git a/services/core/java/com/android/server/wm/ActivityTaskManagerService.java b/services/core/java/com/android/server/wm/ActivityTaskManagerService.java
index 61eb9d4..182d1a0 100644
--- a/services/core/java/com/android/server/wm/ActivityTaskManagerService.java
+++ b/services/core/java/com/android/server/wm/ActivityTaskManagerService.java
@@ -1738,7 +1738,7 @@
if (self.isState(
ActivityStack.ActivityState.RESUMED, ActivityStack.ActivityState.PAUSING)) {
- self.getDisplay().getWindowContainerController().overridePendingAppTransition(
+ self.getDisplay().mDisplayContent.mAppTransition.overridePendingAppTransition(
packageName, enterAnim, exitAnim, null);
}
@@ -3073,12 +3073,11 @@
// Get top display of front most application.
final ActivityStack focusedStack = getTopDisplayFocusedStack();
if (focusedStack != null) {
- final DisplayWindowController dwc =
- focusedStack.getDisplay().getWindowContainerController();
- dwc.prepareAppTransition(TRANSIT_TASK_IN_PLACE, false);
- dwc.overridePendingAppTransitionInPlace(activityOptions.getPackageName(),
+ final DisplayContent dc = focusedStack.getDisplay().mDisplayContent;
+ dc.prepareAppTransition(TRANSIT_TASK_IN_PLACE, false);
+ dc.mAppTransition.overrideInPlaceAppTransition(activityOptions.getPackageName(),
activityOptions.getCustomInPlaceResId());
- dwc.executeAppTransition();
+ dc.executeAppTransition();
}
}
@@ -5770,17 +5769,18 @@
if (activityDisplay == null) {
return;
}
- final DisplayWindowController dwc = activityDisplay.getWindowContainerController();
- final boolean wasTransitionSet = dwc.getPendingAppTransition() != TRANSIT_NONE;
+ final DisplayContent dc = activityDisplay.mDisplayContent;
+ final boolean wasTransitionSet =
+ dc.mAppTransition.getAppTransition() != TRANSIT_NONE;
if (!wasTransitionSet) {
- dwc.prepareAppTransition(TRANSIT_NONE, false /* alwaysKeepCurrent */);
+ dc.prepareAppTransition(TRANSIT_NONE, false /* alwaysKeepCurrent */);
}
mRootActivityContainer.ensureActivitiesVisible(null, 0, !PRESERVE_WINDOWS);
// If there was a transition set already we don't want to interfere with it as we
// might be starting it too early.
if (!wasTransitionSet) {
- dwc.executeAppTransition();
+ dc.executeAppTransition();
}
}
if (callback != null) {
@@ -6270,18 +6270,20 @@
finishInstrumentationCallback.run();
}
- mWindowManager.deferSurfaceLayout();
- try {
- if (!restarting && hasVisibleActivities
- && !mRootActivityContainer.resumeFocusedStacksTopActivities()) {
- // If there was nothing to resume, and we are not already restarting this
- // process, but there is a visible activity that is hosted by the process...
- // then make sure all visible activities are running, taking care of
- // restarting this process.
- mRootActivityContainer.ensureActivitiesVisible(null, 0, !PRESERVE_WINDOWS);
+ if (!restarting && hasVisibleActivities) {
+ mWindowManager.deferSurfaceLayout();
+ try {
+ if (!mRootActivityContainer.resumeFocusedStacksTopActivities()) {
+ // If there was nothing to resume, and we are not already restarting
+ // this process, but there is a visible activity that is hosted by the
+ // process...then make sure all visible activities are running, taking
+ // care of restarting this process.
+ mRootActivityContainer.ensureActivitiesVisible(null, 0,
+ !PRESERVE_WINDOWS);
+ }
+ } finally {
+ mWindowManager.continueSurfaceLayout();
}
- } finally {
- mWindowManager.continueSurfaceLayout();
}
}
}
diff --git a/services/core/java/com/android/server/wm/DisplayContent.java b/services/core/java/com/android/server/wm/DisplayContent.java
index aba2eb3..2f4c5ca 100644
--- a/services/core/java/com/android/server/wm/DisplayContent.java
+++ b/services/core/java/com/android/server/wm/DisplayContent.java
@@ -59,8 +59,11 @@
import static android.view.WindowManager.LayoutParams.TYPE_SYSTEM_ERROR;
import static android.view.WindowManager.LayoutParams.TYPE_TOAST;
import static android.view.WindowManager.LayoutParams.TYPE_WALLPAPER;
+import static android.view.WindowManager.TRANSIT_ACTIVITY_OPEN;
import static android.view.WindowManager.TRANSIT_KEYGUARD_UNOCCLUDE;
+import static android.view.WindowManager.TRANSIT_TASK_OPEN;
+import static android.view.WindowManager.TRANSIT_TASK_TO_FRONT;
import static com.android.server.policy.WindowManagerPolicy.FINISH_LAYOUT_REDO_ANIM;
import static com.android.server.policy.WindowManagerPolicy.FINISH_LAYOUT_REDO_CONFIG;
import static com.android.server.policy.WindowManagerPolicy.FINISH_LAYOUT_REDO_LAYOUT;
@@ -207,6 +210,9 @@
/** Unique identifier of this stack. */
private final int mDisplayId;
+ // TODO: Remove once unification is complete.
+ ActivityDisplay mAcitvityDisplay;
+
/** The containers below are the only child containers the display can have. */
// Contains all window containers that are related to apps (Activities)
private final TaskStackContainers mTaskStackContainers = new TaskStackContainers(mWmService);
@@ -227,7 +233,6 @@
private WindowState mTmpWindow;
private WindowState mTmpWindow2;
- private WindowAnimator mTmpWindowAnimator;
private boolean mTmpRecoveringMemory;
private boolean mUpdateImeTarget;
private boolean mTmpInitial;
@@ -827,12 +832,12 @@
* initialize direct children.
* @param display May not be null.
* @param service You know.
- * @param controller The controller for the display container.
+ * @param activityDisplay The ActivityDisplay for the display container.
*/
DisplayContent(Display display, WindowManagerService service,
- DisplayWindowController controller) {
+ ActivityDisplay activityDisplay) {
super(service);
- setController(controller);
+ mAcitvityDisplay = activityDisplay;
if (service.mRoot.getDisplayContent(display.getDisplayId()) != null) {
throw new IllegalArgumentException("Display with ID=" + display.getDisplayId()
+ " already exists=" + service.mRoot.getDisplayContent(display.getDisplayId())
@@ -1020,11 +1025,6 @@
}
@Override
- DisplayWindowController getController() {
- return (DisplayWindowController) super.getController();
- }
-
- @Override
public Display getDisplay() {
return mDisplay;
}
@@ -1138,6 +1138,17 @@
return true;
}
+ /**
+ * The display content may have configuration set from {@link #DisplayWindowSettings}. This
+ * callback let the owner of container know there is existing configuration to prevent the
+ * values from being replaced by the initializing {@link #ActivityDisplay}.
+ */
+ void initializeDisplayOverrideConfiguration() {
+ if (mAcitvityDisplay != null) {
+ mAcitvityDisplay.onInitializeOverrideConfiguration(getRequestedOverrideConfiguration());
+ }
+ }
+
/** Notify the configuration change of this display. */
void sendNewConfiguration() {
mWmService.mH.obtainMessage(SEND_NEW_CONFIGURATION, this).sendToTarget();
@@ -4686,6 +4697,11 @@
}
void prepareAppTransition(@WindowManager.TransitionType int transit,
+ boolean alwaysKeepCurrent) {
+ prepareAppTransition(transit, alwaysKeepCurrent, 0 /* flags */, false /* forceOverride */);
+ }
+
+ void prepareAppTransition(@WindowManager.TransitionType int transit,
boolean alwaysKeepCurrent, @WindowManager.TransitionFlags int flags,
boolean forceOverride) {
final boolean prepared = mAppTransition.prepareAppTransitionLocked(
@@ -4737,6 +4753,14 @@
pendingLayoutChanges |= changes;
}
+ /** Check if pending app transition is for activity / task launch. */
+ boolean isNextTransitionForward() {
+ final int transit = mAppTransition.getAppTransition();
+ return transit == TRANSIT_ACTIVITY_OPEN
+ || transit == TRANSIT_TASK_OPEN
+ || transit == TRANSIT_TASK_TO_FRONT;
+ }
+
/**
* @see Display#FLAG_SHOULD_SHOW_SYSTEM_DECORATIONS
*/
diff --git a/services/core/java/com/android/server/wm/DisplayPolicy.java b/services/core/java/com/android/server/wm/DisplayPolicy.java
index d4bd91b..8b8cadc 100644
--- a/services/core/java/com/android/server/wm/DisplayPolicy.java
+++ b/services/core/java/com/android/server/wm/DisplayPolicy.java
@@ -763,6 +763,12 @@
|| attrs.hideTimeoutMilliseconds > TOAST_WINDOW_TIMEOUT) {
attrs.hideTimeoutMilliseconds = TOAST_WINDOW_TIMEOUT;
}
+ // Accessibility users may need longer timeout duration. This api compares
+ // original timeout with user's preference and return longer one. It returns
+ // original timeout if there's no preference.
+ attrs.hideTimeoutMilliseconds = mAccessibilityManager.getRecommendedTimeoutMillis(
+ (int) attrs.hideTimeoutMilliseconds,
+ AccessibilityManager.FLAG_CONTENT_TEXT);
attrs.windowAnimations = com.android.internal.R.style.Animation_Toast;
break;
}
diff --git a/services/core/java/com/android/server/wm/DisplayWindowController.java b/services/core/java/com/android/server/wm/DisplayWindowController.java
deleted file mode 100644
index c7eadf9..0000000
--- a/services/core/java/com/android/server/wm/DisplayWindowController.java
+++ /dev/null
@@ -1,357 +0,0 @@
-/*
- * 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.server.wm;
-
-import static android.view.WindowManager.TRANSIT_ACTIVITY_OPEN;
-import static android.view.WindowManager.TRANSIT_TASK_OPEN;
-import static android.view.WindowManager.TRANSIT_TASK_TO_FRONT;
-
-import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_DISPLAY;
-import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_FOCUS_LIGHT;
-import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_STACK;
-import static com.android.server.wm.WindowManagerDebugConfig.TAG_WM;
-import static com.android.server.wm.WindowManagerService.UPDATE_FOCUS_NORMAL;
-
-import android.content.res.Configuration;
-import android.graphics.GraphicBuffer;
-import android.os.Binder;
-import android.os.IBinder;
-import android.os.IRemoteCallback;
-import android.util.Slog;
-import android.view.AppTransitionAnimationSpec;
-import android.view.Display;
-import android.view.WindowManager;
-import android.view.WindowManager.TransitionType;
-
-import com.android.internal.annotations.VisibleForTesting;
-
-/**
- * Controller for the display container. This is created by activity manager to link activity
- * displays to the display content they use in window manager.
- */
-public class DisplayWindowController
- extends WindowContainerController<DisplayContent, WindowContainerListener> {
-
- private final int mDisplayId;
-
- public DisplayWindowController(Display display, WindowContainerListener listener) {
- super(listener, WindowManagerService.getInstance());
- mDisplayId = display.getDisplayId();
-
- synchronized (mGlobalLock) {
- final long callingIdentity = Binder.clearCallingIdentity();
- try {
- mRoot.createDisplayContent(display, this /* controller */);
- } finally {
- Binder.restoreCallingIdentity(callingIdentity);
- }
-
- if (mContainer == null) {
- throw new IllegalArgumentException("Trying to add display=" + display
- + " dc=" + mRoot.getDisplayContent(mDisplayId));
- }
- }
- }
-
- @VisibleForTesting
- public DisplayWindowController(Display display, WindowManagerService service) {
- super(null, service);
- mDisplayId = display.getDisplayId();
- }
-
- @Override
- public void removeContainer() {
- synchronized (mGlobalLock) {
- if(mContainer == null) {
- if (DEBUG_DISPLAY) Slog.i(TAG_WM, "removeDisplay: could not find displayId="
- + mDisplayId);
- return;
- }
- mContainer.removeIfPossible();
- super.removeContainer();
- }
- }
-
- @Override
- public void onRequestedOverrideConfigurationChanged(Configuration overrideConfiguration) {
- synchronized (mGlobalLock) {
- if (mContainer != null) {
- mContainer.mWmService.setNewDisplayOverrideConfiguration(overrideConfiguration,
- mContainer);
- }
- }
- }
-
- /**
- * Updates the docked/pinned controller resources to the current system context.
- */
- public void preOnConfigurationChanged() {
- synchronized (mGlobalLock) {
- if (mContainer != null) {
- mContainer.preOnConfigurationChanged();
- }
- }
- }
-
- /**
- * @see DisplayContent#applyRotationLocked(int, int)
- */
- public void applyRotation(int oldRotation, int newRotation) {
- synchronized (mGlobalLock) {
- if (mContainer != null) {
- mContainer.applyRotationLocked(oldRotation, newRotation);
- }
- }
- }
-
- public int getDisplayId() {
- return mDisplayId;
- }
-
- /**
- * Called when the corresponding display receives
- * {@link android.hardware.display.DisplayManager.DisplayListener#onDisplayChanged(int)}.
- */
- public void onDisplayChanged() {
- synchronized (mGlobalLock) {
- if (mContainer == null) {
- if (DEBUG_DISPLAY) Slog.i(TAG_WM, "onDisplayChanged: could not find display="
- + mDisplayId);
- return;
- }
- mContainer.updateDisplayInfo();
- mService.mWindowPlacerLocked.requestTraversal();
- }
- }
-
- /**
- * Positions the task stack at the given position in the task stack container.
- */
- public void positionChildAt(StackWindowController child, int position,
- boolean includingParents) {
- synchronized (mGlobalLock) {
- if (DEBUG_STACK) Slog.i(TAG_WM, "positionTaskStackAt: positioning stack=" + child
- + " at " + position);
- if (mContainer == null) {
- if (DEBUG_STACK) Slog.i(TAG_WM,
- "positionTaskStackAt: could not find display=" + mContainer);
- return;
- }
- if (child.mContainer == null) {
- if (DEBUG_STACK) Slog.i(TAG_WM,
- "positionTaskStackAt: could not find stack=" + this);
- return;
- }
- mContainer.positionStackAt(position, child.mContainer, includingParents);
- }
- }
-
- /**
- * Starts deferring the ability to update the IME target. This is needed when a call will
- * attempt to update the IME target before all information about the Windows have been updated.
- */
- public void deferUpdateImeTarget() {
- synchronized (mGlobalLock) {
- final DisplayContent dc = mRoot.getDisplayContent(mDisplayId);
- if (dc != null) {
- dc.deferUpdateImeTarget();
- }
- }
- }
-
- /**
- * Resumes updating the IME target after deferring. See {@link #deferUpdateImeTarget()}
- */
- public void continueUpdateImeTarget() {
- synchronized (mGlobalLock) {
- final DisplayContent dc = mRoot.getDisplayContent(mDisplayId);
- if (dc != null) {
- dc.continueUpdateImeTarget();
- }
- }
- }
-
- /**
- * Sets a focused app on this display.
- *
- * @param token Specifies which app should be focused.
- * @param moveFocusNow Specifies if we should update the focused window immediately.
- */
- public void setFocusedApp(IBinder token, boolean moveFocusNow) {
- synchronized (mGlobalLock) {
- if (mContainer == null) {
- if (DEBUG_FOCUS_LIGHT) Slog.i(TAG_WM, "setFocusedApp: could not find displayId="
- + mDisplayId);
- return;
- }
- final AppWindowToken newFocus;
- if (token == null) {
- if (DEBUG_FOCUS_LIGHT) Slog.v(TAG_WM, "Clearing focused app, displayId="
- + mDisplayId);
- newFocus = null;
- } else {
- newFocus = mRoot.getAppWindowToken(token);
- if (newFocus == null) {
- Slog.w(TAG_WM, "Attempted to set focus to non-existing app token: " + token
- + ", displayId=" + mDisplayId);
- }
- if (DEBUG_FOCUS_LIGHT) Slog.v(TAG_WM, "Set focused app to: " + newFocus
- + " moveFocusNow=" + moveFocusNow + " displayId=" + mDisplayId);
- }
-
- final boolean changed = mContainer.setFocusedApp(newFocus);
- if (moveFocusNow && changed) {
- mService.updateFocusedWindowLocked(UPDATE_FOCUS_NORMAL,
- true /*updateInputWindows*/);
- }
- }
- }
-
- public void prepareAppTransition(@WindowManager.TransitionType int transit,
- boolean alwaysKeepCurrent) {
- prepareAppTransition(transit, alwaysKeepCurrent, 0 /* flags */, false /* forceOverride */);
- }
-
- /**
- * @param transit What kind of transition is happening. Use one of the constants
- * AppTransition.TRANSIT_*.
- * @param alwaysKeepCurrent If true and a transition is already set, new transition will NOT
- * be set.
- * @param flags Additional flags for the app transition, Use a combination of the constants
- * AppTransition.TRANSIT_FLAG_*.
- * @param forceOverride Always override the transit, not matter what was set previously.
- */
- public void prepareAppTransition(@WindowManager.TransitionType int transit,
- boolean alwaysKeepCurrent, @WindowManager.TransitionFlags int flags,
- boolean forceOverride) {
- synchronized (mGlobalLock) {
- mRoot.getDisplayContent(mDisplayId).prepareAppTransition(transit, alwaysKeepCurrent,
- flags, forceOverride);
- }
- }
-
- public void executeAppTransition() {
- synchronized (mGlobalLock) {
- mRoot.getDisplayContent(mDisplayId).executeAppTransition();
- }
- }
-
- public void overridePendingAppTransition(String packageName,
- int enterAnim, int exitAnim, IRemoteCallback startedCallback) {
- synchronized (mGlobalLock) {
- mRoot.getDisplayContent(mDisplayId).mAppTransition.overridePendingAppTransition(
- packageName, enterAnim, exitAnim, startedCallback);
- }
- }
-
- public void overridePendingAppTransitionScaleUp(int startX, int startY, int startWidth,
- int startHeight) {
- synchronized (mGlobalLock) {
- mRoot.getDisplayContent(mDisplayId).mAppTransition.overridePendingAppTransitionScaleUp(
- startX, startY, startWidth, startHeight);
- }
- }
-
- public void overridePendingAppTransitionClipReveal(int startX, int startY,
- int startWidth, int startHeight) {
- synchronized (mGlobalLock) {
- mRoot.getDisplayContent(mDisplayId)
- .mAppTransition.overridePendingAppTransitionClipReveal(startX, startY,
- startWidth, startHeight);
- }
- }
-
- public void overridePendingAppTransitionThumb(GraphicBuffer srcThumb, int startX,
- int startY, IRemoteCallback startedCallback, boolean scaleUp) {
- synchronized (mGlobalLock) {
- mRoot.getDisplayContent(mDisplayId)
- .mAppTransition.overridePendingAppTransitionThumb(srcThumb, startX, startY,
- startedCallback, scaleUp);
- }
- }
-
- public void overridePendingAppTransitionAspectScaledThumb(GraphicBuffer srcThumb, int startX,
- int startY, int targetWidth, int targetHeight, IRemoteCallback startedCallback,
- boolean scaleUp) {
- synchronized (mGlobalLock) {
- mRoot.getDisplayContent(mDisplayId)
- .mAppTransition.overridePendingAppTransitionAspectScaledThumb(srcThumb, startX,
- startY, targetWidth, targetHeight, startedCallback, scaleUp);
- }
- }
-
- public void overridePendingAppTransitionMultiThumb(AppTransitionAnimationSpec[] specs,
- IRemoteCallback onAnimationStartedCallback, IRemoteCallback onAnimationFinishedCallback,
- boolean scaleUp) {
- synchronized (mGlobalLock) {
- mRoot.getDisplayContent(mDisplayId)
- .mAppTransition.overridePendingAppTransitionMultiThumb(specs,
- onAnimationStartedCallback, onAnimationFinishedCallback, scaleUp);
- }
- }
-
- public void overridePendingAppTransitionStartCrossProfileApps() {
- synchronized (mGlobalLock) {
- mRoot.getDisplayContent(mDisplayId)
- .mAppTransition.overridePendingAppTransitionStartCrossProfileApps();
- }
- }
-
- public void overridePendingAppTransitionInPlace(String packageName, int anim) {
- synchronized (mGlobalLock) {
- mRoot.getDisplayContent(mDisplayId)
- .mAppTransition.overrideInPlaceAppTransition(packageName, anim);
- }
- }
-
- /**
- * Get Pending App transition of display.
- *
- * @return The pending app transition of the display.
- */
- public @TransitionType int getPendingAppTransition() {
- synchronized (mGlobalLock) {
- return mRoot.getDisplayContent(mDisplayId).mAppTransition.getAppTransition();
- }
- }
-
- /**
- * Check if pending app transition is for activity / task launch.
- */
- public boolean isNextTransitionForward() {
- final int transit = getPendingAppTransition();
- return transit == TRANSIT_ACTIVITY_OPEN
- || transit == TRANSIT_TASK_OPEN
- || transit == TRANSIT_TASK_TO_FRONT;
- }
-
- /**
- * Checks if system decorations should be shown on this display.
- *
- * @see Display#FLAG_SHOULD_SHOW_SYSTEM_DECORATIONS
- */
- public boolean supportsSystemDecorations() {
- synchronized (mGlobalLock) {
- return mContainer.supportsSystemDecorations();
- }
- }
-
- @Override
- public String toString() {
- return "{DisplayWindowController displayId=" + mDisplayId + "}";
- }
-}
diff --git a/services/core/java/com/android/server/wm/KeyguardController.java b/services/core/java/com/android/server/wm/KeyguardController.java
index 4ef3513..5f56fe5 100644
--- a/services/core/java/com/android/server/wm/KeyguardController.java
+++ b/services/core/java/com/android/server/wm/KeyguardController.java
@@ -174,7 +174,7 @@
mWindowManager.deferSurfaceLayout();
try {
setKeyguardGoingAway(true);
- mRootActivityContainer.getDefaultDisplay().getWindowContainerController()
+ mRootActivityContainer.getDefaultDisplay().mDisplayContent
.prepareAppTransition(TRANSIT_KEYGUARD_GOING_AWAY,
false /* alwaysKeepCurrent */, convertTransitFlags(flags),
false /* forceOverride */);
@@ -302,7 +302,7 @@
if (isKeyguardLocked()) {
mWindowManager.deferSurfaceLayout();
try {
- mRootActivityContainer.getDefaultDisplay().getWindowContainerController()
+ mRootActivityContainer.getDefaultDisplay().mDisplayContent
.prepareAppTransition(resolveOccludeTransit(),
false /* alwaysKeepCurrent */, 0 /* flags */,
true /* forceOverride */);
@@ -332,11 +332,11 @@
// If we are about to unocclude the Keyguard, but we can dismiss it without security,
// we immediately dismiss the Keyguard so the activity gets shown without a flicker.
- final DisplayWindowController dwc =
- mRootActivityContainer.getDefaultDisplay().getWindowContainerController();
+ final DisplayContent dc =
+ mRootActivityContainer.getDefaultDisplay().mDisplayContent;
if (mKeyguardShowing && canDismissKeyguard()
- && dwc.getPendingAppTransition() == TRANSIT_KEYGUARD_UNOCCLUDE) {
- dwc.prepareAppTransition(mBeforeUnoccludeTransit, false /* alwaysKeepCurrent */,
+ && dc.mAppTransition.getAppTransition() == TRANSIT_KEYGUARD_UNOCCLUDE) {
+ dc.prepareAppTransition(mBeforeUnoccludeTransit, false /* alwaysKeepCurrent */,
0 /* flags */, true /* forceOverride */);
mRootActivityContainer.ensureActivitiesVisible(null, 0, !PRESERVE_WINDOWS);
mWindowManager.executeAppTransition();
@@ -355,10 +355,10 @@
}
private int resolveOccludeTransit() {
- final DisplayWindowController dwc =
- mRootActivityContainer.getDefaultDisplay().getWindowContainerController();
+ final DisplayContent dc =
+ mService.mRootActivityContainer.getDefaultDisplay().mDisplayContent;
if (mBeforeUnoccludeTransit != TRANSIT_UNSET
- && dwc.getPendingAppTransition() == TRANSIT_KEYGUARD_UNOCCLUDE
+ && dc.mAppTransition.getAppTransition() == TRANSIT_KEYGUARD_UNOCCLUDE
// TODO(b/113840485): Handle app transition for individual display.
&& isDisplayOccluded(DEFAULT_DISPLAY)) {
@@ -369,7 +369,7 @@
} else if (!isDisplayOccluded(DEFAULT_DISPLAY)) {
// Save transit in case we dismiss/occlude Keyguard shortly after.
- mBeforeUnoccludeTransit = dwc.getPendingAppTransition();
+ mBeforeUnoccludeTransit = dc.mAppTransition.getAppTransition();
return TRANSIT_KEYGUARD_UNOCCLUDE;
} else {
return TRANSIT_KEYGUARD_OCCLUDE;
diff --git a/services/core/java/com/android/server/wm/LockTaskController.java b/services/core/java/com/android/server/wm/LockTaskController.java
index d2f2863..3b66f7d 100644
--- a/services/core/java/com/android/server/wm/LockTaskController.java
+++ b/services/core/java/com/android/server/wm/LockTaskController.java
@@ -582,7 +582,7 @@
mSupervisor.mRootActivityContainer.resumeFocusedStacksTopActivities();
final ActivityStack stack = task.getStack();
if (stack != null) {
- stack.getDisplay().getWindowContainerController().executeAppTransition();
+ stack.getDisplay().mDisplayContent.executeAppTransition();
}
} else if (lockTaskModeState != LOCK_TASK_MODE_NONE) {
mSupervisor.handleNonResizableTaskIfNeeded(task, WINDOWING_MODE_UNDEFINED,
diff --git a/services/core/java/com/android/server/wm/RecentsAnimation.java b/services/core/java/com/android/server/wm/RecentsAnimation.java
index 9422182..42cd8e8 100644
--- a/services/core/java/com/android/server/wm/RecentsAnimation.java
+++ b/services/core/java/com/android/server/wm/RecentsAnimation.java
@@ -93,12 +93,12 @@
Trace.traceBegin(TRACE_TAG_ACTIVITY_MANAGER, "RecentsAnimation#startRecentsActivity");
// TODO(multi-display) currently only support recents animation in default display.
- final DisplayWindowController dwc =
- mService.mRootActivityContainer.getDefaultDisplay().getWindowContainerController();
+ final DisplayContent dc =
+ mService.mRootActivityContainer.getDefaultDisplay().mDisplayContent;
if (!mWindowManager.canStartRecentsAnimation()) {
notifyAnimationCancelBeforeStart(recentsAnimationRunner);
if (DEBUG) Slog.d(TAG, "Can't start recents animation, nextAppTransition="
- + dwc.getPendingAppTransition());
+ + dc.mAppTransition.getAppTransition());
return;
}
@@ -107,7 +107,7 @@
&& recentsComponent.equals(intent.getComponent())
? ACTIVITY_TYPE_RECENTS
: ACTIVITY_TYPE_HOME;
- final ActivityStack targetStack = mDefaultDisplay.getStack(WINDOWING_MODE_UNDEFINED,
+ ActivityStack targetStack = mDefaultDisplay.getStack(WINDOWING_MODE_UNDEFINED,
mTargetActivityType);
ActivityRecord targetActivity = getTargetActivity(targetStack, intent.getComponent());
final boolean hasExistingActivity = targetActivity != null;
@@ -153,7 +153,7 @@
"startRecentsActivity");
}
} else {
- // No recents activity
+ // No recents activity, create the new recents activity bottom most
ActivityOptions options = ActivityOptions.makeBasic();
options.setLaunchActivityType(mTargetActivityType);
options.setAvoidMoveToFront();
@@ -166,11 +166,20 @@
.setActivityOptions(SafeActivityOptions.fromBundle(options.toBundle()))
.setMayWait(userId)
.execute();
+
+ // Move the recents activity into place for the animation
+ targetActivity = mDefaultDisplay.getStack(WINDOWING_MODE_UNDEFINED,
+ mTargetActivityType).getTopActivity();
+ targetStack = targetActivity.getActivityStack();
+ mDefaultDisplay.moveStackBehindBottomMostVisibleStack(targetStack);
+ if (DEBUG) {
+ Slog.d(TAG, "Moved stack=" + targetStack + " behind stack="
+ + mDefaultDisplay.getStackAbove(targetStack));
+ }
+
mWindowManager.prepareAppTransition(TRANSIT_NONE, false);
mWindowManager.executeAppTransition();
- targetActivity = mDefaultDisplay.getStack(WINDOWING_MODE_UNDEFINED,
- mTargetActivityType).getTopActivity();
// TODO: Maybe wait for app to draw in this particular case?
diff --git a/services/core/java/com/android/server/wm/RootActivityContainer.java b/services/core/java/com/android/server/wm/RootActivityContainer.java
index f7877c0..c5b42f9 100644
--- a/services/core/java/com/android/server/wm/RootActivityContainer.java
+++ b/services/core/java/com/android/server/wm/RootActivityContainer.java
@@ -914,7 +914,7 @@
void executeAppTransitionForAllDisplay() {
for (int displayNdx = mActivityDisplays.size() - 1; displayNdx >= 0; --displayNdx) {
final ActivityDisplay display = mActivityDisplays.get(displayNdx);
- display.getWindowContainerController().executeAppTransition();
+ display.mDisplayContent.executeAppTransition();
}
}
@@ -1254,9 +1254,8 @@
}
// TODO: remove after object merge with RootWindowContainer
- void onChildPositionChanged(DisplayWindowController childController, int position) {
+ void onChildPositionChanged(ActivityDisplay display, int position) {
// Assume AM lock is held from positionChildAt of controller in each hierarchy.
- final ActivityDisplay display = getActivityDisplay(childController.getDisplayId());
if (display != null) {
positionChildAt(display, position);
}
@@ -1281,8 +1280,7 @@
@VisibleForTesting
void addChild(ActivityDisplay activityDisplay, int position) {
positionChildAt(activityDisplay, position);
- mRootWindowContainer.positionChildAt(position,
- activityDisplay.getWindowContainerController().mContainer);
+ mRootWindowContainer.positionChildAt(position, activityDisplay.mDisplayContent);
}
void removeChild(ActivityDisplay activityDisplay) {
diff --git a/services/core/java/com/android/server/wm/RootWindowContainer.java b/services/core/java/com/android/server/wm/RootWindowContainer.java
index 3a5c578..3bbef92 100644
--- a/services/core/java/com/android/server/wm/RootWindowContainer.java
+++ b/services/core/java/com/android/server/wm/RootWindowContainer.java
@@ -224,7 +224,7 @@
return null;
}
- DisplayContent createDisplayContent(final Display display, DisplayWindowController controller) {
+ DisplayContent createDisplayContent(final Display display, ActivityDisplay activityDisplay) {
final int displayId = display.getDisplayId();
// In select scenarios, it is possible that a DisplayContent will be created on demand
@@ -233,17 +233,17 @@
final DisplayContent existing = getDisplayContent(displayId);
if (existing != null) {
- initializeDisplayOverrideConfiguration(controller, existing);
- existing.setController(controller);
+ existing.mAcitvityDisplay = activityDisplay;
+ existing.initializeDisplayOverrideConfiguration();
return existing;
}
- final DisplayContent dc = new DisplayContent(display, mWmService, controller);
+ final DisplayContent dc = new DisplayContent(display, mWmService, activityDisplay);
if (DEBUG_DISPLAY) Slog.v(TAG_WM, "Adding display=" + display);
mWmService.mDisplayWindowSettings.applySettingsToDisplayLocked(dc);
- initializeDisplayOverrideConfiguration(controller, dc);
+ dc.initializeDisplayOverrideConfiguration();
if (mWmService.mDisplayManagerInternal != null) {
mWmService.mDisplayManagerInternal.setDisplayInfoOverrideFromWindowManager(
@@ -256,19 +256,6 @@
return dc;
}
- /**
- * The display content may have configuration set from {@link #DisplayWindowSettings}. This
- * callback let the owner of container know there is existing configuration to prevent the
- * values from being replaced by the initializing {@link #ActivityDisplay}.
- */
- private void initializeDisplayOverrideConfiguration(DisplayWindowController controller,
- DisplayContent displayContent) {
- if (controller != null && controller.mListener != null) {
- controller.mListener.onInitializeOverrideConfiguration(
- displayContent.getRequestedOverrideConfiguration());
- }
- }
-
boolean isLayoutNeeded() {
final int numDisplays = mChildren.size();
for (int displayNdx = 0; displayNdx < numDisplays; ++displayNdx) {
@@ -1040,7 +1027,7 @@
void positionChildAt(int position, DisplayContent child, boolean includingParents) {
super.positionChildAt(position, child, includingParents);
if (mRootActivityContainer != null) {
- mRootActivityContainer.onChildPositionChanged(child.getController(), position);
+ mRootActivityContainer.onChildPositionChanged(child.mAcitvityDisplay, position);
}
}
diff --git a/services/core/jni/Android.bp b/services/core/jni/Android.bp
index b85489a..6d72191 100644
--- a/services/core/jni/Android.bp
+++ b/services/core/jni/Android.bp
@@ -126,7 +126,6 @@
static_libs: [
"android.hardware.broadcastradio@common-utils-1x-lib",
- "libscrypt_static",
],
product_variables: {
diff --git a/services/core/jni/com_android_server_location_GnssLocationProvider.cpp b/services/core/jni/com_android_server_location_GnssLocationProvider.cpp
index 4d0556c..0e349b7 100644
--- a/services/core/jni/com_android_server_location_GnssLocationProvider.cpp
+++ b/services/core/jni/com_android_server_location_GnssLocationProvider.cpp
@@ -756,14 +756,18 @@
Return<void> gnssMeasurementCb(const IGnssMeasurementCallback_V1_1::GnssData& data) override;
Return<void> GnssMeasurementCb(const IGnssMeasurementCallback_V1_0::GnssData& data) override;
private:
- void translateGnssMeasurement_V1_0(
- const IGnssMeasurementCallback_V1_0::GnssMeasurement* measurement,
- JavaObject& object);
- jobjectArray translateGnssMeasurements(
- JNIEnv* env,
- const IGnssMeasurementCallback_V1_1::GnssMeasurement* measurements_v1_1,
- const IGnssMeasurementCallback_V1_0::GnssMeasurement* measurements_v1_0,
- size_t count);
+ template<class T>
+ void translateSingleGnssMeasurement(const T* measurement, JavaObject& object);
+
+ template<class T>
+ jobjectArray translateAllGnssMeasurements(JNIEnv* env, const T* measurements, size_t count);
+
+ template<class T>
+ void translateAndSetGnssData(const T& data);
+
+ template<class T>
+ size_t getMeasurementCount(const T& data);
+
jobject translateGnssClock(
JNIEnv* env, const IGnssMeasurementCallback_V1_0::GnssClock* clock);
void setMeasurementData(JNIEnv* env, jobject clock, jobjectArray measurementArray);
@@ -777,41 +781,48 @@
Return<void> GnssMeasurementCallback::gnssMeasurementCb(
const IGnssMeasurementCallback_V1_1::GnssData& data) {
- JNIEnv* env = getJniEnv();
-
- jobject clock;
- jobjectArray measurementArray;
-
- clock = translateGnssClock(env, &data.clock);
-
- measurementArray = translateGnssMeasurements(
- env, data.measurements.data(), nullptr, data.measurements.size());
- setMeasurementData(env, clock, measurementArray);
-
- env->DeleteLocalRef(clock);
- env->DeleteLocalRef(measurementArray);
+ translateAndSetGnssData(data);
return Void();
}
Return<void> GnssMeasurementCallback::GnssMeasurementCb(
const IGnssMeasurementCallback_V1_0::GnssData& data) {
+ translateAndSetGnssData(data);
+ return Void();
+}
+
+template<class T>
+void GnssMeasurementCallback::translateAndSetGnssData(const T& data) {
JNIEnv* env = getJniEnv();
jobject clock;
jobjectArray measurementArray;
clock = translateGnssClock(env, &data.clock);
- measurementArray = translateGnssMeasurements(
- env, nullptr, data.measurements.data(), data.measurementCount);
+ size_t count = getMeasurementCount(data);
+ measurementArray = translateAllGnssMeasurements(env, data.measurements.data(), count);
setMeasurementData(env, clock, measurementArray);
env->DeleteLocalRef(clock);
env->DeleteLocalRef(measurementArray);
- return Void();
}
-// preallocate object as: JavaObject object(env, "android/location/GnssMeasurement");
-void GnssMeasurementCallback::translateGnssMeasurement_V1_0(
+template<>
+size_t GnssMeasurementCallback::getMeasurementCount<IGnssMeasurementCallback_V1_0::GnssData>
+ (const IGnssMeasurementCallback_V1_0::GnssData& data) {
+ return data.measurementCount;
+}
+
+template<>
+size_t GnssMeasurementCallback::getMeasurementCount<IGnssMeasurementCallback_V1_1::GnssData>
+ (const IGnssMeasurementCallback_V1_1::GnssData& data) {
+ return data.measurements.size();
+}
+
+// Preallocate object as: JavaObject object(env, "android/location/GnssMeasurement");
+template<>
+void GnssMeasurementCallback::translateSingleGnssMeasurement
+ <IGnssMeasurementCallback_V1_0::GnssMeasurement>(
const IGnssMeasurementCallback_V1_0::GnssMeasurement* measurement,
JavaObject& object) {
uint32_t flags = static_cast<uint32_t>(measurement->flags);
@@ -852,6 +863,20 @@
}
}
+// Preallocate object as: JavaObject object(env, "android/location/GnssMeasurement");
+template<>
+void GnssMeasurementCallback::translateSingleGnssMeasurement
+ <IGnssMeasurementCallback_V1_1::GnssMeasurement>(
+ const IGnssMeasurementCallback_V1_1::GnssMeasurement* measurement_V1_1,
+ JavaObject& object) {
+ translateSingleGnssMeasurement(&(measurement_V1_1->v1_0), object);
+
+ // Set the V1_1 flag, and mark that new field has valid information for Java Layer
+ SET(AccumulatedDeltaRangeState,
+ (static_cast<int32_t>(measurement_V1_1->accumulatedDeltaRangeState) |
+ ADR_STATE_HALF_CYCLE_REPORTED));
+}
+
jobject GnssMeasurementCallback::translateGnssClock(
JNIEnv* env, const IGnssMeasurementCallback_V1_0::GnssClock* clock) {
JavaObject object(env, "android/location/GnssClock");
@@ -891,10 +916,10 @@
return object.get();
}
-jobjectArray GnssMeasurementCallback::translateGnssMeasurements(JNIEnv* env,
- const IGnssMeasurementCallback_V1_1::GnssMeasurement* measurements_v1_1,
- const IGnssMeasurementCallback_V1_0::GnssMeasurement* measurements_v1_0,
- size_t count) {
+template<class T>
+jobjectArray GnssMeasurementCallback::translateAllGnssMeasurements(JNIEnv* env,
+ const T* measurements,
+ size_t count) {
if (count == 0) {
return nullptr;
}
@@ -907,17 +932,7 @@
for (uint16_t i = 0; i < count; ++i) {
JavaObject object(env, "android/location/GnssMeasurement");
- if (measurements_v1_1 != nullptr) {
- translateGnssMeasurement_V1_0(&(measurements_v1_1[i].v1_0), object);
-
- // Set the V1_1 flag, and mark that new field has valid information for Java Layer
- SET(AccumulatedDeltaRangeState,
- (static_cast<int32_t>(measurements_v1_1[i].accumulatedDeltaRangeState) |
- ADR_STATE_HALF_CYCLE_REPORTED));
- } else {
- translateGnssMeasurement_V1_0(&(measurements_v1_0[i]), object);
- }
-
+ translateSingleGnssMeasurement(&(measurements[i]), object);
env->SetObjectArrayElement(gnssMeasurementArray, i, object.get());
}
diff --git a/services/core/jni/com_android_server_locksettings_SyntheticPasswordManager.cpp b/services/core/jni/com_android_server_locksettings_SyntheticPasswordManager.cpp
index bc13fde..9dd6032 100644
--- a/services/core/jni/com_android_server_locksettings_SyntheticPasswordManager.cpp
+++ b/services/core/jni/com_android_server_locksettings_SyntheticPasswordManager.cpp
@@ -27,10 +27,6 @@
#include <gatekeeper/password_handle.h>
-extern "C" {
-#include "crypto_scrypt.h"
-}
-
namespace android {
static jlong android_server_SyntheticPasswordManager_nativeSidFromPasswordHandle(JNIEnv* env, jobject, jbyteArray handleArray) {
@@ -48,38 +44,9 @@
}
}
-static jbyteArray android_server_SyntheticPasswordManager_nativeScrypt(JNIEnv* env, jobject, jbyteArray password, jbyteArray salt, jint N, jint r, jint p, jint outLen) {
- if (!password || !salt) {
- return NULL;
- }
-
- int passwordLen = env->GetArrayLength(password);
- int saltLen = env->GetArrayLength(salt);
- jbyteArray ret = env->NewByteArray(outLen);
-
- jbyte* passwordPtr = (jbyte*)env->GetByteArrayElements(password, NULL);
- jbyte* saltPtr = (jbyte*)env->GetByteArrayElements(salt, NULL);
- jbyte* retPtr = (jbyte*)env->GetByteArrayElements(ret, NULL);
-
- int rc = crypto_scrypt((const uint8_t *)passwordPtr, passwordLen,
- (const uint8_t *)saltPtr, saltLen, N, r, p, (uint8_t *)retPtr,
- outLen);
- env->ReleaseByteArrayElements(password, passwordPtr, JNI_ABORT);
- env->ReleaseByteArrayElements(salt, saltPtr, JNI_ABORT);
- env->ReleaseByteArrayElements(ret, retPtr, 0);
-
- if (!rc) {
- return ret;
- } else {
- SLOGE("scrypt failed");
- return NULL;
- }
-}
-
static const JNINativeMethod sMethods[] = {
/* name, signature, funcPtr */
{"nativeSidFromPasswordHandle", "([B)J", (void*)android_server_SyntheticPasswordManager_nativeSidFromPasswordHandle},
- {"nativeScrypt", "([B[BIIII)[B", (void*)android_server_SyntheticPasswordManager_nativeScrypt},
};
int register_android_server_SyntheticPasswordManager(JNIEnv* env) {
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/BaseIDevicePolicyManager.java b/services/devicepolicy/java/com/android/server/devicepolicy/BaseIDevicePolicyManager.java
index 65d3245..c44f306 100644
--- a/services/devicepolicy/java/com/android/server/devicepolicy/BaseIDevicePolicyManager.java
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/BaseIDevicePolicyManager.java
@@ -81,7 +81,8 @@
}
@Override
- public void setGlobalPrivateDns(ComponentName who, int mode, String privateDnsHost) {
+ public int setGlobalPrivateDns(ComponentName who, int mode, String privateDnsHost) {
+ return DevicePolicyManager.PRIVATE_DNS_SET_ERROR_FAILURE_SETTING;
}
@Override
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
index f68f4d7..bfbaac9 100644
--- a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
@@ -59,6 +59,8 @@
import static android.app.admin.DevicePolicyManager.PRIVATE_DNS_MODE_OPPORTUNISTIC;
import static android.app.admin.DevicePolicyManager.PRIVATE_DNS_MODE_PROVIDER_HOSTNAME;
import static android.app.admin.DevicePolicyManager.PRIVATE_DNS_MODE_UNKNOWN;
+import static android.app.admin.DevicePolicyManager.PRIVATE_DNS_SET_ERROR_FAILURE_SETTING;
+import static android.app.admin.DevicePolicyManager.PRIVATE_DNS_SET_SUCCESS;
import static android.app.admin.DevicePolicyManager.PROFILE_KEYGUARD_FEATURES_AFFECT_OWNER;
import static android.app.admin.DevicePolicyManager.WIPE_EUICC;
import static android.app.admin.DevicePolicyManager.WIPE_EXTERNAL_STORAGE;
@@ -109,6 +111,7 @@
import android.app.admin.DeviceAdminInfo;
import android.app.admin.DeviceAdminReceiver;
import android.app.admin.DevicePolicyCache;
+import android.app.admin.DevicePolicyEventLogger;
import android.app.admin.DevicePolicyManager;
import android.app.admin.DevicePolicyManagerInternal;
import android.app.admin.NetworkEvent;
@@ -195,6 +198,7 @@
import android.security.keystore.KeyGenParameterSpec;
import android.security.keystore.ParcelableKeyGenParameterSpec;
import android.service.persistentdata.PersistentDataBlockManager;
+import android.stats.devicepolicy.DevicePolicyEnums;
import android.telephony.TelephonyManager;
import android.telephony.data.ApnSetting;
import android.text.TextUtils;
@@ -205,7 +209,6 @@
import android.util.Pair;
import android.util.Slog;
import android.util.SparseArray;
-import android.util.StatsLog;
import android.util.Xml;
import android.view.IWindowManager;
import android.view.accessibility.AccessibilityManager;
@@ -4051,6 +4054,12 @@
}
maybeLogPasswordComplexitySet(who, userId, parent, metrics);
}
+ DevicePolicyEventLogger
+ .createEvent(DevicePolicyEnums.SET_PASSWORD_QUALITY)
+ .setAdmin(who)
+ .setInt(quality)
+ .setBoolean(parent)
+ .write();
}
/**
@@ -4164,6 +4173,11 @@
}
maybeLogPasswordComplexitySet(who, userId, parent, metrics);
}
+ DevicePolicyEventLogger
+ .createEvent(DevicePolicyEnums.SET_PASSWORD_MINIMUM_LENGTH)
+ .setAdmin(who)
+ .setInt(length)
+ .write();
}
@Override
@@ -4391,6 +4405,11 @@
}
maybeLogPasswordComplexitySet(who, userId, parent, metrics);
}
+ DevicePolicyEventLogger
+ .createEvent(DevicePolicyEnums.SET_PASSWORD_MINIMUM_UPPER_CASE)
+ .setAdmin(who)
+ .setInt(length)
+ .write();
}
@Override
@@ -4414,6 +4433,11 @@
}
maybeLogPasswordComplexitySet(who, userId, parent, metrics);
}
+ DevicePolicyEventLogger
+ .createEvent(DevicePolicyEnums.SET_PASSWORD_MINIMUM_LOWER_CASE)
+ .setAdmin(who)
+ .setInt(length)
+ .write();
}
@Override
@@ -4440,6 +4464,11 @@
}
maybeLogPasswordComplexitySet(who, userId, parent, metrics);
}
+ DevicePolicyEventLogger
+ .createEvent(DevicePolicyEnums.SET_PASSWORD_MINIMUM_LETTERS)
+ .setAdmin(who)
+ .setInt(length)
+ .write();
}
@Override
@@ -4466,6 +4495,11 @@
}
maybeLogPasswordComplexitySet(who, userId, parent, metrics);
}
+ DevicePolicyEventLogger
+ .createEvent(DevicePolicyEnums.SET_PASSWORD_MINIMUM_NUMERIC)
+ .setAdmin(who)
+ .setInt(length)
+ .write();
}
@Override
@@ -4492,6 +4526,11 @@
}
maybeLogPasswordComplexitySet(who, userId, parent, metrics);
}
+ DevicePolicyEventLogger
+ .createEvent(DevicePolicyEnums.SET_PASSWORD_MINIMUM_SYMBOLS)
+ .setAdmin(who)
+ .setInt(length)
+ .write();
}
@Override
@@ -4518,6 +4557,11 @@
}
maybeLogPasswordComplexitySet(who, userId, parent, metrics);
}
+ DevicePolicyEventLogger
+ .createEvent(DevicePolicyEnums.SET_PASSWORD_MINIMUM_NON_LETTER)
+ .setAdmin(who)
+ .setInt(length)
+ .write();
}
@Override
@@ -4890,14 +4934,16 @@
private boolean resetPasswordInternal(String password, long tokenHandle, byte[] token,
int flags, int callingUid, int userHandle) {
int quality;
+ final int realQuality;
synchronized (getLockObject()) {
quality = getPasswordQuality(null, userHandle, /* parent */ false);
if (quality == DevicePolicyManager.PASSWORD_QUALITY_MANAGED) {
quality = PASSWORD_QUALITY_UNSPECIFIED;
}
final PasswordMetrics metrics = PasswordMetrics.computeForPassword(password);
+ realQuality = metrics.quality;
if (quality != PASSWORD_QUALITY_UNSPECIFIED) {
- final int realQuality = metrics.quality;
+
if (realQuality < quality
&& quality != DevicePolicyManager.PASSWORD_QUALITY_COMPLEX) {
Slog.w(LOG_TAG, "resetPassword: password quality 0x"
@@ -4984,7 +5030,7 @@
try {
if (token == null) {
if (!TextUtils.isEmpty(password)) {
- mLockPatternUtils.saveLockPassword(password, null, quality, userHandle);
+ mLockPatternUtils.saveLockPassword(password, null, realQuality, userHandle);
} else {
mLockPatternUtils.clearLock(null, userHandle);
}
@@ -4993,7 +5039,7 @@
result = mLockPatternUtils.setLockCredentialWithToken(password,
TextUtils.isEmpty(password) ? LockPatternUtils.CREDENTIAL_TYPE_NONE
: LockPatternUtils.CREDENTIAL_TYPE_PASSWORD,
- quality, tokenHandle, token, userHandle);
+ realQuality, tokenHandle, token, userHandle);
}
boolean requireEntry = (flags & DevicePolicyManager.RESET_PASSWORD_REQUIRE_ENTRY) != 0;
if (requireEntry) {
@@ -5285,6 +5331,10 @@
mInjector.binderRestoreCallingIdentity(ident);
}
}
+ DevicePolicyEventLogger
+ .createEvent(DevicePolicyEnums.LOCK_NOW)
+ .setInt(flags)
+ .write();
}
@Override
@@ -5363,6 +5413,12 @@
final long id = mInjector.binderClearCallingIdentity();
try {
alias = mCertificateMonitor.installCaCert(userHandle, certBuffer);
+ final boolean isDelegate = (admin == null);
+ DevicePolicyEventLogger
+ .createEvent(DevicePolicyEnums.INSTALL_CA_CERT)
+ .setAdmin(callerPackage)
+ .setBoolean(isDelegate)
+ .write();
if (alias == null) {
Log.w(LOG_TAG, "Problem installing cert");
return false;
@@ -5422,6 +5478,12 @@
keyChain.setGrant(callingUid, alias, true);
}
keyChain.setUserSelectable(alias, isUserSelectable);
+ final boolean isDelegate = (who == null);
+ DevicePolicyEventLogger
+ .createEvent(DevicePolicyEnums.INSTALL_KEY_PAIR)
+ .setAdmin(callerPackage)
+ .setBoolean(isDelegate)
+ .write();
return true;
} catch (RemoteException e) {
Log.e(LOG_TAG, "Installing certificate", e);
@@ -6116,6 +6178,11 @@
synchronized (getLockObject()) {
admin = getActiveAdminForCallerLocked(null, DeviceAdminInfo.USES_POLICY_WIPE_DATA);
}
+ DevicePolicyEventLogger
+ .createEvent(DevicePolicyEnums.WIPE_DATA_WITH_REASON)
+ .setAdmin(admin.info.getComponent())
+ .setInt(flags)
+ .write();
String internalReason = "DevicePolicyManager.wipeDataWithReason() from "
+ admin.info.getComponent().flattenToShortString();
wipeDataNoLock(
@@ -7220,6 +7287,12 @@
SecurityLog.writeEvent(SecurityLog.TAG_KEYGUARD_DISABLED_FEATURES_SET,
who.getPackageName(), userHandle, affectedUserId, which);
}
+ DevicePolicyEventLogger
+ .createEvent(DevicePolicyEnums.SET_KEYGUARD_DISABLED_FEATURES)
+ .setAdmin(who)
+ .setInt(which)
+ .setBoolean(parent)
+ .write();
}
/**
@@ -9466,7 +9539,14 @@
}
saveUserRestrictionsLocked(userHandle);
}
- StatsLog.write(StatsLog.USER_RESTRICTION_CHANGED, key, enabledFromThisOwner);
+ final int eventId = enabledFromThisOwner
+ ? DevicePolicyEnums.ADD_USER_RESTRICTION
+ : DevicePolicyEnums.REMOVE_USER_RESTRICTION;
+ DevicePolicyEventLogger
+ .createEvent(eventId)
+ .setAdmin(who)
+ .setStrings(key)
+ .write();
if (SecurityLog.isLoggingEnabled()) {
final int eventTag = enabledFromThisOwner
? SecurityLog.TAG_USER_RESTRICTION_ADDED
@@ -10238,6 +10318,11 @@
try {
setUserRestriction(who, UserManager.DISALLOW_INSTALL_UNKNOWN_SOURCES,
(Integer.parseInt(value) == 0) ? true : false);
+ DevicePolicyEventLogger
+ .createEvent(DevicePolicyEnums.SET_SECURE_SETTING)
+ .setAdmin(who)
+ .setStrings(setting, value)
+ .write();
} catch (NumberFormatException exc) {
Slog.e(LOG_TAG, "Invalid value: " + value + " for setting " + setting);
}
@@ -10265,6 +10350,11 @@
mInjector.binderRestoreCallingIdentity(id);
}
}
+ DevicePolicyEventLogger
+ .createEvent(DevicePolicyEnums.SET_SECURE_SETTING)
+ .setAdmin(who)
+ .setStrings(setting, value)
+ .write();
}
@Override
@@ -10623,6 +10713,10 @@
synchronized (getLockObject()) {
updateMaximumTimeToLockLocked(userId);
}
+ DevicePolicyEventLogger
+ .createEvent(DevicePolicyEnums.SEPARATE_PROFILE_CHALLENGE_CHANGED)
+ .setBoolean(isSeparateProfileChallengeEnabled(userId))
+ .write();
}
@Override
@@ -10963,6 +11057,13 @@
saveSettingsLocked(userId);
}
}
+ final boolean isDelegate = (admin == null);
+ DevicePolicyEventLogger
+ .createEvent(DevicePolicyEnums.SET_PERMISSION_POLICY)
+ .setAdmin(callerPackage)
+ .setInt(policy)
+ .setBoolean(isDelegate)
+ .write();
}
@Override
@@ -11014,7 +11115,6 @@
PackageManager.FLAG_PERMISSION_POLICY_FIXED, 0, user);
} break;
}
- return true;
} catch (SecurityException se) {
return false;
} catch (NameNotFoundException e) {
@@ -11023,6 +11123,15 @@
mInjector.binderRestoreCallingIdentity(ident);
}
}
+ final boolean isDelegate = (admin == null);
+ DevicePolicyEventLogger
+ .createEvent(DevicePolicyEnums.SET_PERMISSION_GRANT_STATE)
+ .setAdmin(callerPackage)
+ .setStrings(permission)
+ .setInt(grantState)
+ .setBoolean(isDelegate)
+ .write();
+ return true;
}
@Override
@@ -11848,6 +11957,11 @@
mSecurityLogMonitor.stop();
}
}
+ DevicePolicyEventLogger
+ .createEvent(DevicePolicyEnums.SET_SECURITY_LOGGING_ENABLED)
+ .setAdmin(admin)
+ .setBoolean(enabled)
+ .write();
}
@Override
@@ -11885,13 +11999,17 @@
Preconditions.checkNotNull(admin);
ensureDeviceOwnerAndAllUsersAffiliated(admin);
+ DevicePolicyEventLogger
+ .createEvent(DevicePolicyEnums.RETRIEVE_PRE_REBOOT_SECURITY_LOGS)
+ .setAdmin(admin)
+ .write();
+
if (!mContext.getResources().getBoolean(R.bool.config_supportPreRebootSecurityLogs)
|| !mInjector.securityLogGetLoggingEnabledProperty()) {
return null;
}
recordSecurityLogRetrievalTime();
-
ArrayList<SecurityEvent> output = new ArrayList<SecurityEvent>();
try {
SecurityLog.readPreviousEvents(output);
@@ -11918,6 +12036,10 @@
recordSecurityLogRetrievalTime();
List<SecurityEvent> logs = mSecurityLogMonitor.retrieveLogs();
+ DevicePolicyEventLogger
+ .createEvent(DevicePolicyEnums.RETRIEVE_SECURITY_LOGS)
+ .setAdmin(admin)
+ .write();
return logs != null ? new ParceledListSlice<SecurityEvent>(logs) : null;
}
@@ -13278,32 +13400,40 @@
}
@Override
- public void setGlobalPrivateDns(@NonNull ComponentName who, int mode, String privateDnsHost) {
+ public int setGlobalPrivateDns(@NonNull ComponentName who, int mode, String privateDnsHost) {
if (!mHasFeature) {
- return;
+ return PRIVATE_DNS_SET_ERROR_FAILURE_SETTING;
}
Preconditions.checkNotNull(who, "ComponentName is null");
enforceDeviceOwner(who);
+ final int returnCode;
+
switch (mode) {
case PRIVATE_DNS_MODE_OPPORTUNISTIC:
if (!TextUtils.isEmpty(privateDnsHost)) {
- throw new IllegalArgumentException("A DNS host should not be provided when " +
- "setting opportunistic mode.");
+ throw new IllegalArgumentException(
+ "Host provided for opportunistic mode, but is not needed.");
}
putPrivateDnsSettings(ConnectivityManager.PRIVATE_DNS_MODE_OPPORTUNISTIC, null);
- break;
+ return PRIVATE_DNS_SET_SUCCESS;
case PRIVATE_DNS_MODE_PROVIDER_HOSTNAME:
- if (!NetworkUtils.isWeaklyValidatedHostname(privateDnsHost)) {
+ if (TextUtils.isEmpty(privateDnsHost)
+ || !NetworkUtils.isWeaklyValidatedHostname(privateDnsHost)) {
throw new IllegalArgumentException(
- String.format("Provided hostname is not valid: %s", privateDnsHost));
+ String.format("Provided hostname %s is not valid", privateDnsHost));
}
- putPrivateDnsSettings(ConnectivityManager.PRIVATE_DNS_MODE_PROVIDER_HOSTNAME,
+
+ // Connectivity check will have been performed in the DevicePolicyManager before
+ // the call here.
+ putPrivateDnsSettings(
+ ConnectivityManager.PRIVATE_DNS_MODE_PROVIDER_HOSTNAME,
privateDnsHost);
- break;
+ return PRIVATE_DNS_SET_SUCCESS;
default:
- throw new IllegalArgumentException(String.format("Unsupported mode: %d", mode));
+ throw new IllegalArgumentException(
+ String.format("Provided mode, %d, is not a valid mode.", mode));
}
}
diff --git a/services/java/com/android/server/SystemServer.java b/services/java/com/android/server/SystemServer.java
index 2baef6af..88f645d 100644
--- a/services/java/com/android/server/SystemServer.java
+++ b/services/java/com/android/server/SystemServer.java
@@ -36,7 +36,6 @@
import android.content.res.Resources.Theme;
import android.database.sqlite.SQLiteCompatibilityWalFlags;
import android.database.sqlite.SQLiteGlobal;
-import android.hardware.display.ColorDisplayManager;
import android.os.BaseBundle;
import android.os.Binder;
import android.os.Build;
@@ -1443,11 +1442,9 @@
mSystemServiceManager.startService(TwilightService.class);
traceEnd();
- if (ColorDisplayManager.isNightDisplayAvailable(context)) {
- traceBeginAndSlog("StartColorDisplay");
- mSystemServiceManager.startService(ColorDisplayService.class);
- traceEnd();
- }
+ traceBeginAndSlog("StartColorDisplay");
+ mSystemServiceManager.startService(ColorDisplayService.class);
+ traceEnd();
traceBeginAndSlog("StartJobScheduler");
mSystemServiceManager.startService(JobSchedulerService.class);
diff --git a/services/robotests/src/com/android/server/backup/BackupManagerServiceTest.java b/services/robotests/src/com/android/server/backup/BackupManagerServiceTest.java
index ba4caf44..b01adc9 100644
--- a/services/robotests/src/com/android/server/backup/BackupManagerServiceTest.java
+++ b/services/robotests/src/com/android/server/backup/BackupManagerServiceTest.java
@@ -57,7 +57,6 @@
private static final String TEST_TRANSPORT = "transport";
@Mock private UserBackupManagerService mUserBackupManagerService;
- @Mock private TransportManager mTransportManager;
private BackupManagerService mBackupManagerService;
private Context mContext;
@@ -72,10 +71,7 @@
new BackupManagerService(
application,
new Trampoline(application),
- BackupManagerServiceTestUtils.startBackupThread(null),
- new File(application.getCacheDir(), "base_state"),
- new File(application.getCacheDir(), "data"),
- mTransportManager);
+ BackupManagerServiceTestUtils.startBackupThread(null));
mBackupManagerService.setUserBackupManagerService(mUserBackupManagerService);
}
diff --git a/services/robotests/src/com/android/server/backup/UserBackupManagerServiceTest.java b/services/robotests/src/com/android/server/backup/UserBackupManagerServiceTest.java
index 9d43819..efbcb96 100644
--- a/services/robotests/src/com/android/server/backup/UserBackupManagerServiceTest.java
+++ b/services/robotests/src/com/android/server/backup/UserBackupManagerServiceTest.java
@@ -148,7 +148,7 @@
mShadowContext.grantPermissions(android.Manifest.permission.BACKUP);
when(mTransportManager.getTransportCurrentDestinationString(eq(mTransportName)))
.thenReturn("destinationString");
- UserBackupManagerService backupManagerService = createInitializedBackupManagerService();
+ UserBackupManagerService backupManagerService = createUserBackupManagerServiceAndRunTasks();
String destination = backupManagerService.getDestinationString(mTransportName);
@@ -164,7 +164,7 @@
mShadowContext.grantPermissions(android.Manifest.permission.BACKUP);
when(mTransportManager.getTransportCurrentDestinationString(eq(mTransportName)))
.thenThrow(TransportNotRegisteredException.class);
- UserBackupManagerService backupManagerService = createInitializedBackupManagerService();
+ UserBackupManagerService backupManagerService = createUserBackupManagerServiceAndRunTasks();
String destination = backupManagerService.getDestinationString(mTransportName);
@@ -180,7 +180,7 @@
mShadowContext.denyPermissions(android.Manifest.permission.BACKUP);
when(mTransportManager.getTransportCurrentDestinationString(eq(mTransportName)))
.thenThrow(TransportNotRegisteredException.class);
- UserBackupManagerService backupManagerService = createInitializedBackupManagerService();
+ UserBackupManagerService backupManagerService = createUserBackupManagerServiceAndRunTasks();
expectThrows(
SecurityException.class,
@@ -195,7 +195,7 @@
public void testIsAppEligibleForBackup_whenAppNotEligible() throws Exception {
mShadowContext.grantPermissions(android.Manifest.permission.BACKUP);
setUpCurrentTransport(mTransportManager, mTransport);
- UserBackupManagerService backupManagerService = createInitializedBackupManagerService();
+ UserBackupManagerService backupManagerService = createUserBackupManagerServiceAndRunTasks();
boolean result = backupManagerService.isAppEligibleForBackup(PACKAGE_1);
@@ -211,7 +211,7 @@
mShadowContext.grantPermissions(android.Manifest.permission.BACKUP);
TransportMock transportMock = setUpCurrentTransport(mTransportManager, backupTransport());
ShadowAppBackupUtils.setAppRunningAndEligibleForBackupWithTransport(PACKAGE_1);
- UserBackupManagerService backupManagerService = createInitializedBackupManagerService();
+ UserBackupManagerService backupManagerService = createUserBackupManagerServiceAndRunTasks();
boolean result = backupManagerService.isAppEligibleForBackup(PACKAGE_1);
@@ -229,7 +229,7 @@
mShadowContext.denyPermissions(android.Manifest.permission.BACKUP);
setUpCurrentTransport(mTransportManager, mTransport);
ShadowAppBackupUtils.setAppRunningAndEligibleForBackupWithTransport(PACKAGE_1);
- UserBackupManagerService backupManagerService = createInitializedBackupManagerService();
+ UserBackupManagerService backupManagerService = createUserBackupManagerServiceAndRunTasks();
expectThrows(
SecurityException.class,
@@ -246,7 +246,7 @@
mShadowContext.grantPermissions(android.Manifest.permission.BACKUP);
TransportMock transportMock = setUpCurrentTransport(mTransportManager, mTransport);
ShadowAppBackupUtils.setAppRunningAndEligibleForBackupWithTransport(PACKAGE_1);
- UserBackupManagerService backupManagerService = createInitializedBackupManagerService();
+ UserBackupManagerService backupManagerService = createUserBackupManagerServiceAndRunTasks();
String[] filtered =
backupManagerService.filterAppsEligibleForBackup(
@@ -264,7 +264,7 @@
@Test
public void testFilterAppsEligibleForBackup_whenNoneIsEligible() throws Exception {
mShadowContext.grantPermissions(android.Manifest.permission.BACKUP);
- UserBackupManagerService backupManagerService = createInitializedBackupManagerService();
+ UserBackupManagerService backupManagerService = createUserBackupManagerServiceAndRunTasks();
String[] filtered =
backupManagerService.filterAppsEligibleForBackup(
@@ -281,7 +281,7 @@
public void testFilterAppsEligibleForBackup_withoutPermission() throws Exception {
mShadowContext.denyPermissions(android.Manifest.permission.BACKUP);
setUpCurrentTransport(mTransportManager, mTransport);
- UserBackupManagerService backupManagerService = createInitializedBackupManagerService();
+ UserBackupManagerService backupManagerService = createUserBackupManagerServiceAndRunTasks();
expectThrows(
SecurityException.class,
@@ -319,7 +319,7 @@
public void testSelectBackupTransport() throws Exception {
setUpForSelectTransport();
mShadowContext.grantPermissions(android.Manifest.permission.BACKUP);
- UserBackupManagerService backupManagerService = createInitializedBackupManagerService();
+ UserBackupManagerService backupManagerService = createUserBackupManagerServiceAndRunTasks();
String oldTransport =
backupManagerService.selectBackupTransport(mNewTransport.transportName);
@@ -338,7 +338,7 @@
public void testSelectBackupTransport_withoutPermission() throws Exception {
setUpForSelectTransport();
mShadowContext.denyPermissions(android.Manifest.permission.BACKUP);
- UserBackupManagerService backupManagerService = createInitializedBackupManagerService();
+ UserBackupManagerService backupManagerService = createUserBackupManagerServiceAndRunTasks();
expectThrows(
SecurityException.class,
@@ -356,7 +356,7 @@
mShadowContext.grantPermissions(android.Manifest.permission.BACKUP);
when(mTransportManager.registerAndSelectTransport(eq(mNewTransportComponent)))
.thenReturn(BackupManager.SUCCESS);
- UserBackupManagerService backupManagerService = createInitializedBackupManagerService();
+ UserBackupManagerService backupManagerService = createUserBackupManagerServiceAndRunTasks();
ISelectBackupTransportCallback callback = mock(ISelectBackupTransportCallback.class);
backupManagerService.selectBackupTransportAsync(mNewTransportComponent, callback);
@@ -380,7 +380,7 @@
mShadowContext.grantPermissions(android.Manifest.permission.BACKUP);
when(mTransportManager.registerAndSelectTransport(eq(mNewTransportComponent)))
.thenReturn(BackupManager.ERROR_TRANSPORT_UNAVAILABLE);
- UserBackupManagerService backupManagerService = createInitializedBackupManagerService();
+ UserBackupManagerService backupManagerService = createUserBackupManagerServiceAndRunTasks();
ISelectBackupTransportCallback callback = mock(ISelectBackupTransportCallback.class);
backupManagerService.selectBackupTransportAsync(mNewTransportComponent, callback);
@@ -402,7 +402,7 @@
mShadowContext.grantPermissions(android.Manifest.permission.BACKUP);
when(mTransportManager.registerAndSelectTransport(eq(newTransportComponent)))
.thenReturn(BackupManager.SUCCESS);
- UserBackupManagerService backupManagerService = createInitializedBackupManagerService();
+ UserBackupManagerService backupManagerService = createUserBackupManagerServiceAndRunTasks();
ISelectBackupTransportCallback callback = mock(ISelectBackupTransportCallback.class);
backupManagerService.selectBackupTransportAsync(newTransportComponent, callback);
@@ -421,7 +421,7 @@
public void testSelectBackupTransportAsync_withoutPermission() throws Exception {
setUpForSelectTransport();
mShadowContext.denyPermissions(android.Manifest.permission.BACKUP);
- UserBackupManagerService backupManagerService = createInitializedBackupManagerService();
+ UserBackupManagerService backupManagerService = createUserBackupManagerServiceAndRunTasks();
ComponentName newTransportComponent = mNewTransport.getTransportComponent();
expectThrows(
@@ -445,7 +445,7 @@
mShadowContext.grantPermissions(android.Manifest.permission.BACKUP);
when(mTransportManager.getCurrentTransportComponent())
.thenReturn(mTransport.getTransportComponent());
- UserBackupManagerService backupManagerService = createInitializedBackupManagerService();
+ UserBackupManagerService backupManagerService = createUserBackupManagerServiceAndRunTasks();
ComponentName transportComponent = backupManagerService.getCurrentTransportComponent();
@@ -460,7 +460,7 @@
public void testGetCurrentTransportComponent_whenNoTransportSelected() throws Exception {
mShadowContext.grantPermissions(android.Manifest.permission.BACKUP);
when(mTransportManager.getCurrentTransportComponent()).thenReturn(null);
- UserBackupManagerService backupManagerService = createInitializedBackupManagerService();
+ UserBackupManagerService backupManagerService = createUserBackupManagerServiceAndRunTasks();
ComponentName transportComponent = backupManagerService.getCurrentTransportComponent();
@@ -476,7 +476,7 @@
mShadowContext.grantPermissions(android.Manifest.permission.BACKUP);
when(mTransportManager.getCurrentTransportComponent())
.thenThrow(TransportNotRegisteredException.class);
- UserBackupManagerService backupManagerService = createInitializedBackupManagerService();
+ UserBackupManagerService backupManagerService = createUserBackupManagerServiceAndRunTasks();
ComponentName transportComponent = backupManagerService.getCurrentTransportComponent();
@@ -490,7 +490,7 @@
@Test
public void testGetCurrentTransportComponent_withoutPermission() throws Exception {
mShadowContext.denyPermissions(android.Manifest.permission.BACKUP);
- UserBackupManagerService backupManagerService = createInitializedBackupManagerService();
+ UserBackupManagerService backupManagerService = createUserBackupManagerServiceAndRunTasks();
expectThrows(SecurityException.class, backupManagerService::getCurrentTransportComponent);
}
@@ -525,7 +525,7 @@
mShadowContext.grantPermissions(android.Manifest.permission.BACKUP);
Intent configurationIntent = new Intent();
Intent dataManagementIntent = new Intent();
- UserBackupManagerService backupManagerService = createInitializedBackupManagerService();
+ UserBackupManagerService backupManagerService = createUserBackupManagerServiceAndRunTasks();
backupManagerService.updateTransportAttributes(
mTransportUid,
@@ -556,7 +556,7 @@
throws Exception {
setUpForUpdateTransportAttributes();
mShadowContext.grantPermissions(android.Manifest.permission.BACKUP);
- UserBackupManagerService backupManagerService = createInitializedBackupManagerService();
+ UserBackupManagerService backupManagerService = createUserBackupManagerServiceAndRunTasks();
expectThrows(
SecurityException.class,
@@ -581,7 +581,7 @@
throws Exception {
setUpForUpdateTransportAttributes();
mShadowContext.grantPermissions(android.Manifest.permission.BACKUP);
- UserBackupManagerService backupManagerService = createInitializedBackupManagerService();
+ UserBackupManagerService backupManagerService = createUserBackupManagerServiceAndRunTasks();
expectThrows(
RuntimeException.class,
@@ -605,7 +605,7 @@
public void testUpdateTransportAttributes_whenNameNull_throwsException() throws Exception {
setUpForUpdateTransportAttributes();
mShadowContext.grantPermissions(android.Manifest.permission.BACKUP);
- UserBackupManagerService backupManagerService = createInitializedBackupManagerService();
+ UserBackupManagerService backupManagerService = createUserBackupManagerServiceAndRunTasks();
expectThrows(
RuntimeException.class,
@@ -630,7 +630,7 @@
throws Exception {
setUpForUpdateTransportAttributes();
mShadowContext.grantPermissions(android.Manifest.permission.BACKUP);
- UserBackupManagerService backupManagerService = createInitializedBackupManagerService();
+ UserBackupManagerService backupManagerService = createUserBackupManagerServiceAndRunTasks();
expectThrows(
RuntimeException.class,
@@ -657,7 +657,7 @@
throws Exception {
setUpForUpdateTransportAttributes();
mShadowContext.grantPermissions(android.Manifest.permission.BACKUP);
- UserBackupManagerService backupManagerService = createInitializedBackupManagerService();
+ UserBackupManagerService backupManagerService = createUserBackupManagerServiceAndRunTasks();
expectThrows(
RuntimeException.class,
@@ -696,7 +696,7 @@
mShadowContext.grantPermissions(android.Manifest.permission.BACKUP);
Intent configurationIntent = new Intent();
Intent dataManagementIntent = new Intent();
- UserBackupManagerService backupManagerService = createInitializedBackupManagerService();
+ UserBackupManagerService backupManagerService = createUserBackupManagerServiceAndRunTasks();
backupManagerService.updateTransportAttributes(
mTransportUid,
@@ -727,7 +727,7 @@
throws Exception {
setUpForUpdateTransportAttributes();
mShadowContext.denyPermissions(android.Manifest.permission.BACKUP);
- UserBackupManagerService backupManagerService = createInitializedBackupManagerService();
+ UserBackupManagerService backupManagerService = createUserBackupManagerServiceAndRunTasks();
expectThrows(
SecurityException.class,
@@ -766,7 +766,7 @@
@Test
public void testRequestBackup_whenPermissionDenied() throws Exception {
mShadowContext.denyPermissions(android.Manifest.permission.BACKUP);
- UserBackupManagerService backupManagerService = createInitializedBackupManagerService();
+ UserBackupManagerService backupManagerService = createUserBackupManagerServiceAndRunTasks();
expectThrows(
SecurityException.class,
@@ -780,7 +780,7 @@
@Test
public void testRequestBackup_whenPackagesNull() throws Exception {
mShadowContext.grantPermissions(android.Manifest.permission.BACKUP);
- UserBackupManagerService backupManagerService = createInitializedBackupManagerService();
+ UserBackupManagerService backupManagerService = createUserBackupManagerServiceAndRunTasks();
expectThrows(
IllegalArgumentException.class,
@@ -796,7 +796,7 @@
@Test
public void testRequestBackup_whenPackagesEmpty() throws Exception {
mShadowContext.grantPermissions(android.Manifest.permission.BACKUP);
- UserBackupManagerService backupManagerService = createInitializedBackupManagerService();
+ UserBackupManagerService backupManagerService = createUserBackupManagerServiceAndRunTasks();
expectThrows(
IllegalArgumentException.class,
@@ -811,7 +811,7 @@
@Test
public void testRequestBackup_whenBackupDisabled() throws Exception {
mShadowContext.grantPermissions(android.Manifest.permission.BACKUP);
- UserBackupManagerService backupManagerService = createInitializedBackupManagerService();
+ UserBackupManagerService backupManagerService = createUserBackupManagerServiceAndRunTasks();
backupManagerService.setEnabled(false);
int result = backupManagerService.requestBackup(new String[] {PACKAGE_1}, mObserver, 0);
@@ -828,7 +828,7 @@
@Test
public void testRequestBackup_whenNotProvisioned() throws Exception {
mShadowContext.grantPermissions(android.Manifest.permission.BACKUP);
- UserBackupManagerService backupManagerService = createInitializedBackupManagerService();
+ UserBackupManagerService backupManagerService = createUserBackupManagerServiceAndRunTasks();
backupManagerService.setProvisioned(false);
int result = backupManagerService.requestBackup(new String[] {PACKAGE_1}, mObserver, 0);
@@ -846,7 +846,7 @@
public void testRequestBackup_whenTransportNotRegistered() throws Exception {
mShadowContext.grantPermissions(android.Manifest.permission.BACKUP);
setUpCurrentTransport(mTransportManager, mTransport.unregistered());
- UserBackupManagerService backupManagerService = createInitializedBackupManagerService();
+ UserBackupManagerService backupManagerService = createUserBackupManagerServiceAndRunTasks();
backupManagerService.setEnabled(true);
backupManagerService.setProvisioned(true);
@@ -866,7 +866,7 @@
mShadowContext.grantPermissions(android.Manifest.permission.BACKUP);
mShadowPackageManager.addPackage(PACKAGE_1);
setUpCurrentTransport(mTransportManager, mTransport);
- UserBackupManagerService backupManagerService = createInitializedBackupManagerService();
+ UserBackupManagerService backupManagerService = createUserBackupManagerServiceAndRunTasks();
backupManagerService.setEnabled(true);
backupManagerService.setProvisioned(true);
// Haven't set PACKAGE_1 as eligible
@@ -934,7 +934,7 @@
@Config(shadows = {ShadowBinder.class, ShadowKeyValueBackupJob.class})
public void testBackupNow_clearsCallingIdentityForJobScheduler() {
mShadowContext.grantPermissions(android.Manifest.permission.BACKUP);
- UserBackupManagerService backupManagerService = createInitializedBackupManagerService();
+ UserBackupManagerService backupManagerService = createUserBackupManagerServiceAndRunTasks();
setUpPowerManager(backupManagerService);
ShadowBinder.setCallingUid(1);
@@ -952,7 +952,7 @@
@Config(shadows = {ShadowBinder.class, ShadowKeyValueBackupJobException.class})
public void testBackupNow_whenExceptionThrown_restoresCallingIdentity() {
mShadowContext.grantPermissions(android.Manifest.permission.BACKUP);
- UserBackupManagerService backupManagerService = createInitializedBackupManagerService();
+ UserBackupManagerService backupManagerService = createUserBackupManagerServiceAndRunTasks();
setUpPowerManager(backupManagerService);
ShadowBinder.setCallingUid(1);
@@ -963,54 +963,170 @@
}
private UserBackupManagerService createBackupManagerServiceForRequestBackup() {
- UserBackupManagerService backupManagerService = createInitializedBackupManagerService();
+ UserBackupManagerService backupManagerService = createUserBackupManagerServiceAndRunTasks();
backupManagerService.setEnabled(true);
backupManagerService.setProvisioned(true);
return backupManagerService;
}
/**
- * Test verifying that {@link UserBackupManagerService#UserBackupManagerService(Context,
+ * Test verifying that {@link UserBackupManagerService#createAndInitializeService(Context,
* Trampoline, HandlerThread, File, File, TransportManager)} posts a transport registration task
- * to the backup handler thread.
+ * to the backup thread.
*/
@Test
- public void testConstructor_postRegisterTransports() {
+ public void testCreateAndInitializeService_postRegisterTransports() {
mShadowContext.grantPermissions(android.Manifest.permission.BACKUP);
- createBackupManagerService();
-
- mShadowBackupLooper.runToEndOfTasks();
- verify(mTransportManager).registerTransports();
- }
-
- /**
- * Test verifying that the {@link UserBackupManagerService#UserBackupManagerService(Context,
- * Trampoline, HandlerThread, File, File, TransportManager)} does not directly register
- * transports in its own thread.
- */
- @Test
- public void testConstructor_doesNotRegisterTransportsSynchronously() {
- mShadowContext.grantPermissions(android.Manifest.permission.BACKUP);
-
- createBackupManagerService();
-
- // Operations posted to mBackupThread only run with mShadowBackupLooper.runToEndOfTasks()
- verify(mTransportManager, never()).registerTransports();
- }
-
- private UserBackupManagerService createBackupManagerService() {
- return new UserBackupManagerService(
+ UserBackupManagerService.createAndInitializeService(
mContext,
new Trampoline(mContext),
mBackupThread,
mBaseStateDir,
mDataDir,
mTransportManager);
+
+ mShadowBackupLooper.runToEndOfTasks();
+ verify(mTransportManager).registerTransports();
}
- private UserBackupManagerService createInitializedBackupManagerService() {
- return BackupManagerServiceTestUtils.createInitializedUserBackupManagerService(
+ /**
+ * Test verifying that {@link UserBackupManagerService#createAndInitializeService(Context,
+ * Trampoline, HandlerThread, File, File, TransportManager)} does not directly register
+ * transports on the main thread.
+ */
+ @Test
+ public void testCreateAndInitializeService_doesNotRegisterTransportsSynchronously() {
+ mShadowContext.grantPermissions(android.Manifest.permission.BACKUP);
+
+ UserBackupManagerService.createAndInitializeService(
+ mContext,
+ new Trampoline(mContext),
+ mBackupThread,
+ mBaseStateDir,
+ mDataDir,
+ mTransportManager);
+
+ // Operations posted to mBackupThread only run with mShadowBackupLooper.runToEndOfTasks()
+ verify(mTransportManager, never()).registerTransports();
+ }
+
+ /**
+ * Test checking non-null argument on {@link
+ * UserBackupManagerService#createAndInitializeService(Context, Trampoline, HandlerThread, File,
+ * File, TransportManager)}.
+ */
+ @Test
+ public void testCreateAndInitializeService_withNullContext_throws() {
+ expectThrows(
+ NullPointerException.class,
+ () ->
+ UserBackupManagerService.createAndInitializeService(
+ /* context */ null,
+ new Trampoline(mContext),
+ mBackupThread,
+ mBaseStateDir,
+ mDataDir,
+ mTransportManager));
+ }
+
+ /**
+ * Test checking non-null argument on {@link
+ * UserBackupManagerService#createAndInitializeService(Context, Trampoline, HandlerThread, File,
+ * File, TransportManager)}.
+ */
+ @Test
+ public void testCreateAndInitializeService_withNullTrampoline_throws() {
+ expectThrows(
+ NullPointerException.class,
+ () ->
+ UserBackupManagerService.createAndInitializeService(
+ mContext,
+ /* trampoline */ null,
+ mBackupThread,
+ mBaseStateDir,
+ mDataDir,
+ mTransportManager));
+ }
+
+ /**
+ * Test checking non-null argument on {@link
+ * UserBackupManagerService#createAndInitializeService(Context, Trampoline, HandlerThread, File,
+ * File, TransportManager)}.
+ */
+ @Test
+ public void testCreateAndInitializeService_withNullBackupThread_throws() {
+ expectThrows(
+ NullPointerException.class,
+ () ->
+ UserBackupManagerService.createAndInitializeService(
+ mContext,
+ new Trampoline(mContext),
+ /* backupThread */ null,
+ mBaseStateDir,
+ mDataDir,
+ mTransportManager));
+ }
+
+ /**
+ * Test checking non-null argument on {@link
+ * UserBackupManagerService#createAndInitializeService(Context, Trampoline, HandlerThread, File,
+ * File, TransportManager)}.
+ */
+ @Test
+ public void testCreateAndInitializeService_withNullStateDir_throws() {
+ expectThrows(
+ NullPointerException.class,
+ () ->
+ UserBackupManagerService.createAndInitializeService(
+ mContext,
+ new Trampoline(mContext),
+ mBackupThread,
+ /* baseStateDir */ null,
+ mDataDir,
+ mTransportManager));
+ }
+
+ /**
+ * Test checking non-null argument on {@link
+ * UserBackupManagerService#createAndInitializeService(Context, Trampoline, HandlerThread, File,
+ * File, TransportManager)}.
+ */
+ @Test
+ public void testCreateAndInitializeService_withNullDataDir_throws() {
+ expectThrows(
+ NullPointerException.class,
+ () ->
+ UserBackupManagerService.createAndInitializeService(
+ mContext,
+ new Trampoline(mContext),
+ mBackupThread,
+ mBaseStateDir,
+ /* dataDir */ null,
+ mTransportManager));
+ }
+
+ /**
+ * Test checking non-null argument on {@link
+ * UserBackupManagerService#createAndInitializeService(Context, Trampoline, HandlerThread, File,
+ * File, TransportManager)}.
+ */
+ @Test
+ public void testCreateAndInitializeService_withNullTransportManager_throws() {
+ expectThrows(
+ NullPointerException.class,
+ () ->
+ UserBackupManagerService.createAndInitializeService(
+ mContext,
+ new Trampoline(mContext),
+ mBackupThread,
+ mBaseStateDir,
+ mDataDir,
+ /* transportManager */ null));
+ }
+
+ private UserBackupManagerService createUserBackupManagerServiceAndRunTasks() {
+ return BackupManagerServiceTestUtils.createUserBackupManagerServiceAndRunTasks(
mContext, mBackupThread, mBaseStateDir, mDataDir, mTransportManager);
}
diff --git a/services/robotests/src/com/android/server/backup/keyvalue/KeyValueBackupTaskTest.java b/services/robotests/src/com/android/server/backup/keyvalue/KeyValueBackupTaskTest.java
index 1aa4999..099127c 100644
--- a/services/robotests/src/com/android/server/backup/keyvalue/KeyValueBackupTaskTest.java
+++ b/services/robotests/src/com/android/server/backup/keyvalue/KeyValueBackupTaskTest.java
@@ -25,12 +25,9 @@
import static android.app.backup.ForwardingBackupAgent.forward;
import static com.android.server.backup.testing.BackupManagerServiceTestUtils.createBackupWakeLock;
-import static com.android.server.backup.testing.BackupManagerServiceTestUtils
- .createInitializedUserBackupManagerService;
-import static com.android.server.backup.testing.BackupManagerServiceTestUtils
- .setUpBackupManagerServiceBasics;
-import static com.android.server.backup.testing.BackupManagerServiceTestUtils
- .setUpBinderCallerAndApplicationAsSystem;
+import static com.android.server.backup.testing.BackupManagerServiceTestUtils.createUserBackupManagerServiceAndRunTasks;
+import static com.android.server.backup.testing.BackupManagerServiceTestUtils.setUpBackupManagerServiceBasics;
+import static com.android.server.backup.testing.BackupManagerServiceTestUtils.setUpBinderCallerAndApplicationAsSystem;
import static com.android.server.backup.testing.PackageData.PM_PACKAGE;
import static com.android.server.backup.testing.PackageData.fullBackupPackage;
import static com.android.server.backup.testing.PackageData.keyValuePackage;
@@ -226,9 +223,8 @@
// Needed to be able to use a real BMS instead of a mock
setUpBinderCallerAndApplicationAsSystem(mApplication);
mBackupManagerService =
- spy(
- createInitializedUserBackupManagerService(
- mContext, mBaseStateDir, mDataDir, mTransportManager));
+ spy(createUserBackupManagerServiceAndRunTasks(
+ mContext, mBaseStateDir, mDataDir, mTransportManager));
setUpBackupManagerServiceBasics(
mBackupManagerService,
mApplication,
diff --git a/services/robotests/src/com/android/server/backup/testing/BackupManagerServiceTestUtils.java b/services/robotests/src/com/android/server/backup/testing/BackupManagerServiceTestUtils.java
index bacc44e..06f6d21 100644
--- a/services/robotests/src/com/android/server/backup/testing/BackupManagerServiceTestUtils.java
+++ b/services/robotests/src/com/android/server/backup/testing/BackupManagerServiceTestUtils.java
@@ -52,23 +52,36 @@
/** Test utils for {@link UserBackupManagerService} and friends. */
public class BackupManagerServiceTestUtils {
/**
- * If the class-under-test is going to execute methods as the system, it's a good idea to also
- * call {@link #setUpBinderCallerAndApplicationAsSystem(Application)} before this method.
+ * Creates an instance of {@link UserBackupManagerService} with a new backup thread and runs
+ * tasks that were posted to it during instantiation.
+ *
+ * <p>If the class-under-test is going to execute methods as the system, it's a good idea to
+ * also call {@link #setUpBinderCallerAndApplicationAsSystem(Application)} before this method.
+ *
+ * @see #createUserBackupManagerServiceAndRunTasks(Context, HandlerThread, File, File,
+ * TransportManager)
*/
- public static UserBackupManagerService createInitializedUserBackupManagerService(
+ public static UserBackupManagerService createUserBackupManagerServiceAndRunTasks(
Context context, File baseStateDir, File dataDir, TransportManager transportManager) {
- return createInitializedUserBackupManagerService(
+ return createUserBackupManagerServiceAndRunTasks(
context, startBackupThread(null), baseStateDir, dataDir, transportManager);
}
- public static UserBackupManagerService createInitializedUserBackupManagerService(
+ /**
+ * Creates an instance of {@link UserBackupManagerService} with the supplied backup thread
+ * {@code backupThread} and runs tasks that were posted to it during instantiation.
+ *
+ * <p>If the class-under-test is going to execute methods as the system, it's a good idea to
+ * also call {@link #setUpBinderCallerAndApplicationAsSystem(Application)} before this method.
+ */
+ public static UserBackupManagerService createUserBackupManagerServiceAndRunTasks(
Context context,
HandlerThread backupThread,
File baseStateDir,
File dataDir,
TransportManager transportManager) {
UserBackupManagerService backupManagerService =
- new UserBackupManagerService(
+ UserBackupManagerService.createAndInitializeService(
context,
new Trampoline(context),
backupThread,
diff --git a/services/robotests/src/com/android/server/location/GnssGeofenceProviderTest.java b/services/robotests/src/com/android/server/location/GnssGeofenceProviderTest.java
index beb5941..30c7336 100644
--- a/services/robotests/src/com/android/server/location/GnssGeofenceProviderTest.java
+++ b/services/robotests/src/com/android/server/location/GnssGeofenceProviderTest.java
@@ -7,7 +7,6 @@
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
-import android.os.Looper;
import android.os.RemoteException;
import android.platform.test.annotations.Presubmit;
@@ -44,7 +43,7 @@
when(mMockNative.pauseGeofence(anyInt())).thenReturn(true);
when(mMockNative.removeGeofence(anyInt())).thenReturn(true);
when(mMockNative.resumeGeofence(anyInt(), anyInt())).thenReturn(true);
- mTestProvider = new GnssGeofenceProvider(Looper.myLooper(), mMockNative);
+ mTestProvider = new GnssGeofenceProvider(mMockNative);
mTestProvider.addCircularHardwareGeofence(GEOFENCE_ID, LATITUDE,
LONGITUDE, RADIUS, LAST_TRANSITION, MONITOR_TRANSITIONS,
NOTIFICATION_RESPONSIVENESS,
diff --git a/services/robotests/src/com/android/server/location/GnssNavigationMessageProviderTest.java b/services/robotests/src/com/android/server/location/GnssNavigationMessageProviderTest.java
index 59e9a15..aa2a96e 100644
--- a/services/robotests/src/com/android/server/location/GnssNavigationMessageProviderTest.java
+++ b/services/robotests/src/com/android/server/location/GnssNavigationMessageProviderTest.java
@@ -16,6 +16,7 @@
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
import org.robolectric.RobolectricTestRunner;
+import org.robolectric.RuntimeEnvironment;
/**
* Unit tests for {@link GnssNavigationMessageProvider}.
@@ -33,8 +34,8 @@
when(mMockNative.startNavigationMessageCollection()).thenReturn(true);
when(mMockNative.stopNavigationMessageCollection()).thenReturn(true);
- mTestProvider = new GnssNavigationMessageProvider(new Handler(Looper.myLooper()),
- mMockNative) {
+ mTestProvider = new GnssNavigationMessageProvider(RuntimeEnvironment.application,
+ new Handler(Looper.myLooper()), mMockNative) {
@Override
public boolean isGpsEnabled() {
return true;
diff --git a/services/tests/servicestests/Android.bp b/services/tests/servicestests/Android.bp
index e804342..d49e78a 100644
--- a/services/tests/servicestests/Android.bp
+++ b/services/tests/servicestests/Android.bp
@@ -69,10 +69,10 @@
"liblog",
"liblzma",
"libnativehelper",
- "libnetdaidl",
"libui",
"libunwind",
"libutils",
+ "netd_aidl_interface-cpp",
],
dxflags: ["--multi-dex"],
diff --git a/services/tests/servicestests/src/com/android/server/backup/TrampolineTest.java b/services/tests/servicestests/src/com/android/server/backup/TrampolineTest.java
index 7c00299..fd010f1 100644
--- a/services/tests/servicestests/src/com/android/server/backup/TrampolineTest.java
+++ b/services/tests/servicestests/src/com/android/server/backup/TrampolineTest.java
@@ -23,6 +23,7 @@
import static junit.framework.Assert.assertTrue;
import static junit.framework.Assert.fail;
+import static org.mockito.Mockito.never;
import static org.mockito.Mockito.reset;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.verifyNoMoreInteractions;
@@ -43,10 +44,14 @@
import android.os.RemoteException;
import android.os.UserHandle;
import android.platform.test.annotations.Presubmit;
+import android.provider.Settings;
+import android.test.mock.MockContentResolver;
import androidx.test.filters.SmallTest;
import androidx.test.runner.AndroidJUnit4;
+import com.android.internal.util.test.FakeSettingsProvider;
+
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
@@ -97,6 +102,7 @@
private FileDescriptor mFileDescriptorStub = new FileDescriptor();
private TrampolineTestable mTrampoline;
+ private MockContentResolver mContentResolver;
@Before
public void setUp() {
@@ -110,6 +116,10 @@
when(mSuppressFileMock.getParentFile()).thenReturn(mSuppressFileParentMock);
mTrampoline = new TrampolineTestable(mContextMock);
+
+ mContentResolver = new MockContentResolver();
+ mContentResolver.addProvider(Settings.AUTHORITY, new FakeSettingsProvider());
+ when(mContextMock.getContentResolver()).thenReturn(mContentResolver);
}
@Test
@@ -118,6 +128,24 @@
}
@Test
+ public void startServiceForUser_whenMultiUserSettingDisabled_isIgnored() {
+ Settings.Global.putInt(mContentResolver, Settings.Global.BACKUP_MULTI_USER_ENABLED, 0);
+
+ mTrampoline.startServiceForUser(10);
+
+ verify(mBackupManagerServiceMock, never()).startServiceForUser(10);
+ }
+
+ @Test
+ public void startServiceForUser_whenMultiUserSettingEnabled_callsBackupManagerService() {
+ Settings.Global.putInt(mContentResolver, Settings.Global.BACKUP_MULTI_USER_ENABLED, 1);
+
+ mTrampoline.startServiceForUser(10);
+
+ verify(mBackupManagerServiceMock).startServiceForUser(10);
+ }
+
+ @Test
public void initializeService_forUserSystem_successfullyInitialized() {
mTrampoline.initializeService(UserHandle.USER_SYSTEM);
diff --git a/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java b/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java
index 5dc6d83..c3a0dda 100644
--- a/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java
+++ b/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java
@@ -4163,7 +4163,7 @@
// test reset password with token
when(getServices().lockPatternUtils.setLockCredentialWithToken(eq(password),
eq(LockPatternUtils.CREDENTIAL_TYPE_PASSWORD),
- eq(DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED), eq(handle), eq(token),
+ eq(DevicePolicyManager.PASSWORD_QUALITY_ALPHABETIC), eq(handle), eq(token),
eq(UserHandle.USER_SYSTEM)))
.thenReturn(true);
assertTrue(dpm.resetPasswordWithToken(admin1, password, token, 0));
diff --git a/services/tests/servicestests/src/com/android/server/pm/UserManagerTest.java b/services/tests/servicestests/src/com/android/server/pm/UserManagerTest.java
index 7bcb571..823b7a5 100644
--- a/services/tests/servicestests/src/com/android/server/pm/UserManagerTest.java
+++ b/services/tests/servicestests/src/com/android/server/pm/UserManagerTest.java
@@ -16,13 +16,13 @@
package com.android.server.pm;
+import android.app.ActivityManager;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.content.pm.PackageManager;
import android.content.pm.UserInfo;
-import android.app.ActivityManager;
import android.os.Bundle;
import android.os.UserHandle;
import android.os.UserManager;
@@ -162,6 +162,29 @@
}
@MediumTest
+ public void testRemoveUserByHandle() {
+ UserInfo userInfo = createUser("Guest 1", UserInfo.FLAG_GUEST);
+ final UserHandle user = userInfo.getUserHandle();
+ synchronized (mUserRemoveLock) {
+ mUserManager.removeUser(user);
+ long time = System.currentTimeMillis();
+ while (mUserManager.getUserInfo(user.getIdentifier()) != null) {
+ try {
+ mUserRemoveLock.wait(REMOVE_CHECK_INTERVAL_MILLIS);
+ } catch (InterruptedException ie) {
+ Thread.currentThread().interrupt();
+ return;
+ }
+ if (System.currentTimeMillis() - time > REMOVE_TIMEOUT_MILLIS) {
+ fail("Timeout waiting for removeUser. userId = " + user.getIdentifier());
+ }
+ }
+ }
+
+ assertFalse(findUser(userInfo.id));
+ }
+
+ @MediumTest
public void testAddGuest() throws Exception {
UserInfo userInfo1 = createUser("Guest 1", UserInfo.FLAG_GUEST);
UserInfo userInfo2 = createUser("Guest 2", UserInfo.FLAG_GUEST);
@@ -504,9 +527,21 @@
UserInfo user = createUser("User", 0);
assertNotNull(user);
// Switch to the user just created.
- switchUser(user.id);
+ switchUser(user.id, null, true);
// Switch back to the starting user.
- switchUser(startUser);
+ switchUser(startUser, null, true);
+ }
+
+ @LargeTest
+ public void testSwitchUserByHandle() {
+ ActivityManager am = getContext().getSystemService(ActivityManager.class);
+ final int startUser = am.getCurrentUser();
+ UserInfo user = createUser("User", 0);
+ assertNotNull(user);
+ // Switch to the user just created.
+ switchUser(-1, user.getUserHandle(), false);
+ // Switch back to the starting user.
+ switchUser(-1, UserHandle.of(startUser), false);
}
@MediumTest
@@ -544,10 +579,20 @@
}
}
- private void switchUser(int userId) {
+ /**
+ * @param userId value will be used to call switchUser(int) only if ignoreHandle is false.
+ * @param user value will be used to call switchUser(UserHandle) only if ignoreHandle is true.
+ * @param ignoreHandle if true, switchUser(int) will be called with the provided userId,
+ * else, switchUser(UserHandle) will be called with the provided user.
+ */
+ private void switchUser(int userId, UserHandle user, boolean ignoreHandle) {
synchronized (mUserSwitchLock) {
ActivityManager am = getContext().getSystemService(ActivityManager.class);
- am.switchUser(userId);
+ if (ignoreHandle) {
+ am.switchUser(userId);
+ } else {
+ am.switchUser(user);
+ }
long time = System.currentTimeMillis();
try {
mUserSwitchLock.wait(SWITCH_USER_TIMEOUT_MILLIS);
@@ -556,7 +601,8 @@
return;
}
if (System.currentTimeMillis() - time > SWITCH_USER_TIMEOUT_MILLIS) {
- fail("Timeout waiting for the user switch to u" + userId);
+ fail("Timeout waiting for the user switch to u"
+ + (ignoreHandle ? userId : user.getIdentifier()));
}
}
}
diff --git a/services/tests/servicestests/src/com/android/server/signedconfig/SignedConfigTest.java b/services/tests/servicestests/src/com/android/server/signedconfig/SignedConfigTest.java
new file mode 100644
index 0000000..a9d4519
--- /dev/null
+++ b/services/tests/servicestests/src/com/android/server/signedconfig/SignedConfigTest.java
@@ -0,0 +1,328 @@
+/*
+ * 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.server.signedconfig;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import static org.junit.Assert.fail;
+
+import static java.util.Collections.emptySet;
+
+import androidx.test.runner.AndroidJUnit4;
+
+import com.google.common.collect.Sets;
+
+import org.json.JSONException;
+import org.json.JSONObject;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.Set;
+
+
+/**
+ * Tests for {@link SignedConfig}
+ */
+@RunWith(AndroidJUnit4.class)
+public class SignedConfigTest {
+
+ private static Set<String> setOf(String... values) {
+ return Sets.newHashSet(values);
+ }
+
+ @Test
+ public void testParsePerSdkConfigSdkMinMax() throws JSONException, InvalidConfigException {
+ JSONObject json = new JSONObject("{\"minSdk\":2, \"maxSdk\": 3, \"values\": []}");
+ SignedConfig.PerSdkConfig config = SignedConfig.parsePerSdkConfig(json, emptySet());
+ assertThat(config.minSdk).isEqualTo(2);
+ assertThat(config.maxSdk).isEqualTo(3);
+ }
+
+ @Test
+ public void testParsePerSdkConfigNoMinSdk() throws JSONException {
+ JSONObject json = new JSONObject("{\"maxSdk\": 3, \"values\": []}");
+ try {
+ SignedConfig.parsePerSdkConfig(json, emptySet());
+ fail("Expected InvalidConfigException or JSONException");
+ } catch (JSONException | InvalidConfigException e) {
+ // expected
+ }
+ }
+
+ @Test
+ public void testParsePerSdkConfigNoMaxSdk() throws JSONException {
+ JSONObject json = new JSONObject("{\"minSdk\": 1, \"values\": []}");
+ try {
+ SignedConfig.parsePerSdkConfig(json, emptySet());
+ fail("Expected InvalidConfigException or JSONException");
+ } catch (JSONException | InvalidConfigException e) {
+ // expected
+ }
+ }
+
+ @Test
+ public void testParsePerSdkConfigNoValues() throws JSONException {
+ JSONObject json = new JSONObject("{\"minSdk\": 1, \"maxSdk\": 3}");
+ try {
+ SignedConfig.parsePerSdkConfig(json, emptySet());
+ fail("Expected InvalidConfigException or JSONException");
+ } catch (JSONException | InvalidConfigException e) {
+ // expected
+ }
+ }
+
+ @Test
+ public void testParsePerSdkConfigSdkNullMinSdk() throws JSONException, InvalidConfigException {
+ JSONObject json = new JSONObject("{\"minSdk\":null, \"maxSdk\": 3, \"values\": []}");
+ try {
+ SignedConfig.parsePerSdkConfig(json, emptySet());
+ fail("Expected InvalidConfigException or JSONException");
+ } catch (JSONException | InvalidConfigException e) {
+ // expected
+ }
+ }
+
+ @Test
+ public void testParsePerSdkConfigSdkNullMaxSdk() throws JSONException, InvalidConfigException {
+ JSONObject json = new JSONObject("{\"minSdk\":1, \"maxSdk\": null, \"values\": []}");
+ try {
+ SignedConfig.parsePerSdkConfig(json, emptySet());
+ fail("Expected InvalidConfigException or JSONException");
+ } catch (JSONException | InvalidConfigException e) {
+ // expected
+ }
+ }
+
+ @Test
+ public void testParsePerSdkConfigNullValues() throws JSONException {
+ JSONObject json = new JSONObject("{\"minSdk\": 1, \"maxSdk\": 3, \"values\": null}");
+ try {
+ SignedConfig.parsePerSdkConfig(json, emptySet());
+ fail("Expected InvalidConfigException or JSONException");
+ } catch (JSONException | InvalidConfigException e) {
+ // expected
+ }
+ }
+
+ @Test
+ public void testParsePerSdkConfigZeroValues()
+ throws JSONException, InvalidConfigException {
+ JSONObject json = new JSONObject("{\"minSdk\": 1, \"maxSdk\": 3, \"values\": []}");
+ SignedConfig.PerSdkConfig config = SignedConfig.parsePerSdkConfig(json, setOf("a", "b"));
+ assertThat(config.values).hasSize(0);
+ }
+
+ @Test
+ public void testParsePerSdkConfigSingleKey()
+ throws JSONException, InvalidConfigException {
+ JSONObject json = new JSONObject(
+ "{\"minSdk\": 1, \"maxSdk\": 1, \"values\": [{\"key\":\"a\", \"value\": \"1\"}]}");
+ SignedConfig.PerSdkConfig config = SignedConfig.parsePerSdkConfig(json, setOf("a", "b"));
+ assertThat(config.values).containsExactly("a", "1");
+ }
+
+ @Test
+ public void testParsePerSdkConfigMultiKeys()
+ throws JSONException, InvalidConfigException {
+ JSONObject json = new JSONObject(
+ "{\"minSdk\": 1, \"maxSdk\": 1, \"values\": [{\"key\":\"a\", \"value\": \"1\"}, "
+ + "{\"key\":\"c\", \"value\": \"2\"}]}");
+ SignedConfig.PerSdkConfig config = SignedConfig.parsePerSdkConfig(
+ json, setOf("a", "b", "c"));
+ assertThat(config.values).containsExactly("a", "1", "c", "2");
+ }
+
+ @Test
+ public void testParsePerSdkConfigSingleKeyNotAllowed() throws JSONException {
+ JSONObject json = new JSONObject(
+ "{\"minSdk\": 1, \"maxSdk\": 1, \"values\": [{\"key\":\"a\", \"value\": \"1\"}]}");
+ try {
+ SignedConfig.parsePerSdkConfig(json, setOf("b"));
+ fail("Expected InvalidConfigException or JSONException");
+ } catch (JSONException | InvalidConfigException e) {
+ // expected
+ }
+ }
+
+ @Test
+ public void testParsePerSdkConfigSingleKeyNoValue()
+ throws JSONException, InvalidConfigException {
+ JSONObject json = new JSONObject(
+ "{\"minSdk\": 1, \"maxSdk\": 1, \"values\": [{\"key\":\"a\"}]}");
+ SignedConfig.PerSdkConfig config = SignedConfig.parsePerSdkConfig(json, setOf("a", "b"));
+ assertThat(config.values).containsExactly("a", null);
+ }
+
+ @Test
+ public void testParsePerSdkConfigValuesInvalid() throws JSONException {
+ JSONObject json = new JSONObject("{\"minSdk\": 1, \"maxSdk\": 1, \"values\": \"foo\"}");
+ try {
+ SignedConfig.parsePerSdkConfig(json, emptySet());
+ fail("Expected InvalidConfigException or JSONException");
+ } catch (JSONException | InvalidConfigException e) {
+ // expected
+ }
+ }
+
+ @Test
+ public void testParsePerSdkConfigConfigEntryInvalid() throws JSONException {
+ JSONObject json = new JSONObject("{\"minSdk\": 1, \"maxSdk\": 1, \"values\": [1, 2]}");
+ try {
+ SignedConfig.parsePerSdkConfig(json, emptySet());
+ fail("Expected InvalidConfigException or JSONException");
+ } catch (JSONException | InvalidConfigException e) {
+ // expected
+ }
+ }
+
+ @Test
+ public void testParsePerSdkConfigConfigEntryNull() throws JSONException {
+ JSONObject json = new JSONObject("{\"minSdk\": 1, \"maxSdk\": 1, \"values\": [null]}");
+ try {
+ SignedConfig.parsePerSdkConfig(json, emptySet());
+ fail("Expected InvalidConfigException or JSONException");
+ } catch (JSONException | InvalidConfigException e) {
+ // expected
+ }
+ }
+
+ @Test
+ public void testParseVersion() throws InvalidConfigException {
+ SignedConfig config = SignedConfig.parse(
+ "{\"version\": 1, \"config\": []}", emptySet());
+ assertThat(config.version).isEqualTo(1);
+ }
+
+ @Test
+ public void testParseVersionInvalid() {
+ try {
+ SignedConfig.parse("{\"version\": \"notanint\", \"config\": []}", emptySet());
+ fail("Expected InvalidConfigException");
+ } catch (InvalidConfigException e) {
+ //expected
+ }
+ }
+
+ @Test
+ public void testParseNoVersion() {
+ try {
+ SignedConfig.parse("{\"config\": []}", emptySet());
+ fail("Expected InvalidConfigException");
+ } catch (InvalidConfigException e) {
+ //expected
+ }
+ }
+
+ @Test
+ public void testParseNoConfig() {
+ try {
+ SignedConfig.parse("{\"version\": 1}", emptySet());
+ fail("Expected InvalidConfigException");
+ } catch (InvalidConfigException e) {
+ //expected
+ }
+ }
+
+ @Test
+ public void testParseConfigNull() {
+ try {
+ SignedConfig.parse("{\"version\": 1, \"config\": null}", emptySet());
+ fail("Expected InvalidConfigException");
+ } catch (InvalidConfigException e) {
+ //expected
+ }
+ }
+
+ @Test
+ public void testParseVersionNull() {
+ try {
+ SignedConfig.parse("{\"version\": null, \"config\": []}", emptySet());
+ fail("Expected InvalidConfigException");
+ } catch (InvalidConfigException e) {
+ //expected
+ }
+ }
+
+ @Test
+ public void testParseConfigInvalidEntry() {
+ try {
+ SignedConfig.parse("{\"version\": 1, \"config\": [{}]}", emptySet());
+ fail("Expected InvalidConfigException");
+ } catch (InvalidConfigException e) {
+ //expected
+ }
+ }
+
+ @Test
+ public void testParseSdkConfigSingle() throws InvalidConfigException {
+ SignedConfig config = SignedConfig.parse(
+ "{\"version\": 1, \"config\":[{\"minSdk\": 1, \"maxSdk\": 1, \"values\": []}]}",
+ emptySet());
+ assertThat(config.perSdkConfig).hasSize(1);
+ }
+
+ @Test
+ public void testParseSdkConfigMultiple() throws InvalidConfigException {
+ SignedConfig config = SignedConfig.parse(
+ "{\"version\": 1, \"config\":[{\"minSdk\": 1, \"maxSdk\": 1, \"values\": []}, "
+ + "{\"minSdk\": 2, \"maxSdk\": 2, \"values\": []}]}", emptySet());
+ assertThat(config.perSdkConfig).hasSize(2);
+ }
+
+ @Test
+ public void testGetMatchingConfigFirst() {
+ SignedConfig.PerSdkConfig sdk1 = new SignedConfig.PerSdkConfig(
+ 1, 1, Collections.emptyMap());
+ SignedConfig.PerSdkConfig sdk2 = new SignedConfig.PerSdkConfig(
+ 2, 2, Collections.emptyMap());
+ SignedConfig config = new SignedConfig(0, Arrays.asList(sdk1, sdk2));
+ assertThat(config.getMatchingConfig(1)).isEqualTo(sdk1);
+ }
+
+ @Test
+ public void testGetMatchingConfigSecond() {
+ SignedConfig.PerSdkConfig sdk1 = new SignedConfig.PerSdkConfig(
+ 1, 1, Collections.emptyMap());
+ SignedConfig.PerSdkConfig sdk2 = new SignedConfig.PerSdkConfig(
+ 2, 2, Collections.emptyMap());
+ SignedConfig config = new SignedConfig(0, Arrays.asList(sdk1, sdk2));
+ assertThat(config.getMatchingConfig(2)).isEqualTo(sdk2);
+ }
+
+ @Test
+ public void testGetMatchingConfigInRange() {
+ SignedConfig.PerSdkConfig sdk13 = new SignedConfig.PerSdkConfig(
+ 1, 3, Collections.emptyMap());
+ SignedConfig.PerSdkConfig sdk46 = new SignedConfig.PerSdkConfig(
+ 4, 6, Collections.emptyMap());
+ SignedConfig config = new SignedConfig(0, Arrays.asList(sdk13, sdk46));
+ assertThat(config.getMatchingConfig(2)).isEqualTo(sdk13);
+ }
+
+ @Test
+ public void testGetMatchingConfigNoMatch() {
+ SignedConfig.PerSdkConfig sdk1 = new SignedConfig.PerSdkConfig(
+ 1, 1, Collections.emptyMap());
+ SignedConfig.PerSdkConfig sdk2 = new SignedConfig.PerSdkConfig(
+ 2, 2, Collections.emptyMap());
+ SignedConfig config = new SignedConfig(0, Arrays.asList(sdk1, sdk2));
+ assertThat(config.getMatchingConfig(3)).isNull();
+ }
+
+}
diff --git a/services/tests/uiservicestests/Android.bp b/services/tests/uiservicestests/Android.bp
index ca8cc0d..7a5eaa8 100644
--- a/services/tests/uiservicestests/Android.bp
+++ b/services/tests/uiservicestests/Android.bp
@@ -50,9 +50,9 @@
"liblog",
"liblzma",
"libnativehelper",
- "libnetdaidl",
"libui",
"libunwindstack",
"libutils",
+ "netd_aidl_interface-cpp",
],
}
diff --git a/services/tests/uiservicestests/src/com/android/server/slice/PinnedSliceStateTest.java b/services/tests/uiservicestests/src/com/android/server/slice/PinnedSliceStateTest.java
index 82e0fbe..a71aca5 100644
--- a/services/tests/uiservicestests/src/com/android/server/slice/PinnedSliceStateTest.java
+++ b/services/tests/uiservicestests/src/com/android/server/slice/PinnedSliceStateTest.java
@@ -106,8 +106,8 @@
mPinnedSliceManager.pin("pkg", FIRST_SPECS, mToken);
TestableLooper.get(this).processAllMessages();
- verify(mIContentProvider).call(anyString(), eq(SliceProvider.METHOD_PIN), eq(null),
- argThat(b -> {
+ verify(mIContentProvider).call(anyString(), anyString(), eq(SliceProvider.METHOD_PIN),
+ eq(null), argThat(b -> {
assertEquals(TEST_URI, b.getParcelable(SliceProvider.EXTRA_BIND_URI));
return true;
}));
diff --git a/services/tests/wmtests/src/com/android/server/wm/ActivityTestsBase.java b/services/tests/wmtests/src/com/android/server/wm/ActivityTestsBase.java
index 3a56419..f553c35 100644
--- a/services/tests/wmtests/src/com/android/server/wm/ActivityTestsBase.java
+++ b/services/tests/wmtests/src/com/android/server/wm/ActivityTestsBase.java
@@ -408,6 +408,7 @@
initialize(intentFirewall, intentController, looper);
initRootActivityContainerMocks(wm);
setWindowManager(wm);
+ createDefaultDisplay();
}
void initRootActivityContainerMocks(WindowManagerService wm) {
@@ -424,7 +425,9 @@
// Called when moving activity to pinned stack.
doNothing().when(mRootActivityContainer).ensureActivitiesVisible(any(), anyInt(),
anyBoolean());
+ }
+ void createDefaultDisplay() {
// Create a default display and put a home stack on it so that we'll always have
// something focusable.
mDefaultDisplay = TestActivityDisplay.create(mStackSupervisor, DEFAULT_DISPLAY);
@@ -598,10 +601,8 @@
}
@Override
- protected DisplayWindowController createWindowContainerController() {
- DisplayWindowController out = mock(DisplayWindowController.class);
- out.mContainer = WindowTestUtils.createTestDisplayContent();
- return out;
+ protected DisplayContent createDisplayContent() {
+ return WindowTestUtils.createTestDisplayContent();
}
void removeAllTasks() {
@@ -616,6 +617,7 @@
private static WindowManagerService prepareMockWindowManager() {
final WindowManagerService service = mock(WindowManagerService.class);
+ service.mRoot = mock(RootWindowContainer.class);
doAnswer((InvocationOnMock invocationOnMock) -> {
final Runnable runnable = invocationOnMock.<Runnable>getArgument(0);
diff --git a/services/tests/wmtests/src/com/android/server/wm/AppTransitionTests.java b/services/tests/wmtests/src/com/android/server/wm/AppTransitionTests.java
index 577859c..fa42289 100644
--- a/services/tests/wmtests/src/com/android/server/wm/AppTransitionTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/AppTransitionTests.java
@@ -80,7 +80,7 @@
@Test
public void testForceOverride() {
mWm.prepareAppTransition(TRANSIT_KEYGUARD_UNOCCLUDE, false /* alwaysKeepCurrent */);
- mDc.getController().prepareAppTransition(TRANSIT_ACTIVITY_OPEN,
+ mDc.prepareAppTransition(TRANSIT_ACTIVITY_OPEN,
false /* alwaysKeepCurrent */, 0 /* flags */, true /* forceOverride */);
assertEquals(TRANSIT_ACTIVITY_OPEN, mDc.mAppTransition.getAppTransition());
}
@@ -102,8 +102,8 @@
@Test
public void testAppTransitionStateForMultiDisplay() {
// Create 2 displays & presume both display the state is ON for ready to display & animate.
- final DisplayContent dc1 = createNewDisplayWithController(Display.STATE_ON);
- final DisplayContent dc2 = createNewDisplayWithController(Display.STATE_ON);
+ final DisplayContent dc1 = createNewDisplay(Display.STATE_ON);
+ final DisplayContent dc2 = createNewDisplay(Display.STATE_ON);
// Create 2 app window tokens to represent 2 activity window.
final WindowTestUtils.TestAppWindowToken token1 = createTestAppWindowToken(dc1,
@@ -117,10 +117,10 @@
// Simulate activity resume / finish flows to prepare app transition & set visibility,
// make sure transition is set as expected for each display.
- dc1.getController().prepareAppTransition(TRANSIT_ACTIVITY_OPEN,
+ dc1.prepareAppTransition(TRANSIT_ACTIVITY_OPEN,
false /* alwaysKeepCurrent */, 0 /* flags */, false /* forceOverride */);
assertEquals(TRANSIT_ACTIVITY_OPEN, dc1.mAppTransition.getAppTransition());
- dc2.getController().prepareAppTransition(TRANSIT_ACTIVITY_CLOSE,
+ dc2.prepareAppTransition(TRANSIT_ACTIVITY_CLOSE,
false /* alwaysKeepCurrent */, 0 /* flags */, false /* forceOverride */);
assertEquals(TRANSIT_ACTIVITY_CLOSE, dc2.mAppTransition.getAppTransition());
// One activity window is visible for resuming & the other activity window is invisible
@@ -138,8 +138,8 @@
@Test
public void testCleanAppTransitionWhenTaskStackReparent() {
// Create 2 displays & presume both display the state is ON for ready to display & animate.
- final DisplayContent dc1 = createNewDisplayWithController(Display.STATE_ON);
- final DisplayContent dc2 = createNewDisplayWithController(Display.STATE_ON);
+ final DisplayContent dc1 = createNewDisplay(Display.STATE_ON);
+ final DisplayContent dc2 = createNewDisplay(Display.STATE_ON);
final TaskStack stack1 = createTaskStackOnDisplay(dc1);
final Task task1 = createTaskInStack(stack1, 0 /* userId */);
@@ -151,7 +151,7 @@
dc1.mClosingApps.add(token1);
assertTrue(dc1.mClosingApps.size() > 0);
- dc1.getController().prepareAppTransition(TRANSIT_ACTIVITY_OPEN,
+ dc1.prepareAppTransition(TRANSIT_ACTIVITY_OPEN,
false /* alwaysKeepCurrent */, 0 /* flags */, false /* forceOverride */);
assertEquals(TRANSIT_ACTIVITY_OPEN, dc1.mAppTransition.getAppTransition());
assertTrue(dc1.mAppTransition.isTransitionSet());
diff --git a/services/tests/wmtests/src/com/android/server/wm/RecentTasksTest.java b/services/tests/wmtests/src/com/android/server/wm/RecentTasksTest.java
index 3c7b4b1..3e025f6 100644
--- a/services/tests/wmtests/src/com/android/server/wm/RecentTasksTest.java
+++ b/services/tests/wmtests/src/com/android/server/wm/RecentTasksTest.java
@@ -875,8 +875,8 @@
}
@Override
- void initRootActivityContainerMocks(WindowManagerService wm) {
- super.initRootActivityContainerMocks(wm);
+ void createDefaultDisplay() {
+ super.createDefaultDisplay();
mDisplay = mRootActivityContainer.getActivityDisplay(DEFAULT_DISPLAY);
mOtherDisplay = TestActivityDisplay.create(mTestStackSupervisor, DEFAULT_DISPLAY + 1);
mRootActivityContainer.addChild(mOtherDisplay, ActivityDisplay.POSITION_TOP);
diff --git a/services/tests/wmtests/src/com/android/server/wm/UnknownAppVisibilityControllerTest.java b/services/tests/wmtests/src/com/android/server/wm/UnknownAppVisibilityControllerTest.java
index 612f9ad..8854ede 100644
--- a/services/tests/wmtests/src/com/android/server/wm/UnknownAppVisibilityControllerTest.java
+++ b/services/tests/wmtests/src/com/android/server/wm/UnknownAppVisibilityControllerTest.java
@@ -49,7 +49,7 @@
mDisplayContent.mUnknownAppVisibilityController.notifyRelayouted(token);
// Make sure our handler processed the message.
- SystemClock.sleep(100);
+ mWm.mH.runWithScissors(() -> { }, 0);
assertTrue(mDisplayContent.mUnknownAppVisibilityController.allResolved());
}
@@ -65,7 +65,7 @@
mDisplayContent.mUnknownAppVisibilityController.notifyRelayouted(token2);
// Make sure our handler processed the message.
- SystemClock.sleep(100);
+ mWm.mH.runWithScissors(() -> { }, 0);
assertTrue(mDisplayContent.mUnknownAppVisibilityController.allResolved());
}
diff --git a/services/tests/wmtests/src/com/android/server/wm/WindowManagerServiceRule.java b/services/tests/wmtests/src/com/android/server/wm/WindowManagerServiceRule.java
index 50fd188..522ab9f 100644
--- a/services/tests/wmtests/src/com/android/server/wm/WindowManagerServiceRule.java
+++ b/services/tests/wmtests/src/com/android/server/wm/WindowManagerServiceRule.java
@@ -149,10 +149,9 @@
mService.onInitReady();
final Display display = mService.mDisplayManager.getDisplay(DEFAULT_DISPLAY);
- final DisplayWindowController dcw = new DisplayWindowController(display, mService);
// Display creation is driven by the ActivityManagerService via
// ActivityStackSupervisor. We emulate those steps here.
- mService.mRoot.createDisplayContent(display, dcw);
+ mService.mRoot.createDisplayContent(display, mock(ActivityDisplay.class));
}
private void removeServices() {
diff --git a/services/tests/wmtests/src/com/android/server/wm/WindowTestUtils.java b/services/tests/wmtests/src/com/android/server/wm/WindowTestUtils.java
index aa0ecf8..65e1835 100644
--- a/services/tests/wmtests/src/com/android/server/wm/WindowTestUtils.java
+++ b/services/tests/wmtests/src/com/android/server/wm/WindowTestUtils.java
@@ -58,8 +58,8 @@
public static class TestDisplayContent extends DisplayContent {
private TestDisplayContent(Display display, WindowManagerService service,
- DisplayWindowController controller) {
- super(display, service, controller);
+ ActivityDisplay activityDisplay) {
+ super(display, service, activityDisplay);
}
/**
diff --git a/services/tests/wmtests/src/com/android/server/wm/WindowTestsBase.java b/services/tests/wmtests/src/com/android/server/wm/WindowTestsBase.java
index 4394f9a..5c3368b 100644
--- a/services/tests/wmtests/src/com/android/server/wm/WindowTestsBase.java
+++ b/services/tests/wmtests/src/com/android/server/wm/WindowTestsBase.java
@@ -360,21 +360,17 @@
final Display display = new Display(DisplayManagerGlobal.getInstance(), displayId,
displayInfo, DEFAULT_DISPLAY_ADJUSTMENTS);
synchronized (mWm.mGlobalLock) {
- return new DisplayContent(display, mWm, mock(DisplayWindowController.class));
+ return new DisplayContent(display, mWm, mock(ActivityDisplay.class));
}
}
/**
* Creates a {@link DisplayContent} with given display state and adds it to the system.
*
- * Unlike {@link #createNewDisplay()} that uses a mock {@link DisplayWindowController} to
- * initialize {@link DisplayContent}, this method used real controller object when the test
- * need to verify its related flows.
- *
* @param displayState For initializing the state of the display. See
* {@link Display#getState()}.
*/
- DisplayContent createNewDisplayWithController(int displayState) {
+ DisplayContent createNewDisplay(int displayState) {
// Leverage main display info & initialize it with display state for given displayId.
DisplayInfo displayInfo = new DisplayInfo();
displayInfo.copyFrom(mDisplayInfo);
@@ -382,11 +378,11 @@
final int displayId = sNextDisplayId++;
final Display display = new Display(DisplayManagerGlobal.getInstance(), displayId,
displayInfo, DEFAULT_DISPLAY_ADJUSTMENTS);
- final DisplayWindowController dcw = new DisplayWindowController(display, mWm);
synchronized (mWm.mGlobalLock) {
// Display creation is driven by DisplayWindowController via ActivityStackSupervisor.
// We skip those steps here.
- return mWm.mRoot.createDisplayContent(display, dcw);
+ final ActivityDisplay mockAd = mock(ActivityDisplay.class);
+ return mWm.mRoot.createDisplayContent(display, mockAd);
}
}
diff --git a/telephony/java/android/telephony/CarrierConfigManager.java b/telephony/java/android/telephony/CarrierConfigManager.java
index 0a60e34..60eb18c 100644
--- a/telephony/java/android/telephony/CarrierConfigManager.java
+++ b/telephony/java/android/telephony/CarrierConfigManager.java
@@ -78,6 +78,15 @@
// system image, that can be added in packages/apps/CarrierConfig.
/**
+ * Specifies a value that identifies the version of the carrier configuration that is
+ * currently in use. This string is displayed on the UI.
+ * The format of the string is not specified.
+ * @hide
+ */
+ public static final String KEY_CARRIER_CONFIG_VERSION_STRING =
+ "carrier_config_version_string";
+
+ /**
* This flag specifies whether VoLTE availability is based on provisioning. By default this is
* false.
*/
@@ -2392,6 +2401,7 @@
static {
sDefaults = new PersistableBundle();
+ sDefaults.putString(KEY_CARRIER_CONFIG_VERSION_STRING, "");
sDefaults.putBoolean(KEY_ALLOW_HOLD_IN_IMS_CALL_BOOL, true);
sDefaults.putBoolean(KEY_CARRIER_ALLOW_DEFLECT_IMS_CALL_BOOL, false);
sDefaults.putBoolean(KEY_ALWAYS_PLAY_REMOTE_HOLD_TONE_BOOL, false);
diff --git a/telephony/java/android/telephony/PhoneNumberUtils.java b/telephony/java/android/telephony/PhoneNumberUtils.java
index f6e8d34..c95837e 100644
--- a/telephony/java/android/telephony/PhoneNumberUtils.java
+++ b/telephony/java/android/telephony/PhoneNumberUtils.java
@@ -1738,7 +1738,10 @@
* @param number the number to look up.
* @return true if the number is in the list of emergency numbers
* listed in the RIL / SIM, otherwise return false.
+ *
+ * @deprecated Please use {@link TelephonyManager#isCurrentEmergencyNumber(String)} instead.
*/
+ @Deprecated
public static boolean isEmergencyNumber(String number) {
return isEmergencyNumber(getDefaultVoiceSubId(), number);
}
@@ -1751,8 +1754,13 @@
* @param number the number to look up.
* @return true if the number is in the list of emergency numbers
* listed in the RIL / SIM, otherwise return false.
+ *
+ * @deprecated Please use {@link TelephonyManager#isCurrentEmergencyNumber(String)}
+ * instead.
+ *
* @hide
*/
+ @Deprecated
@UnsupportedAppUsage
public static boolean isEmergencyNumber(int subId, String number) {
// Return true only if the specified number *exactly* matches
@@ -1778,8 +1786,12 @@
* listed in the RIL / SIM, *or* if the number starts with the
* same digits as any of those emergency numbers.
*
+ * @deprecated Please use {@link TelephonyManager#isCurrentPotentialEmergencyNumber(String)}
+ * instead.
+ *
* @hide
*/
+ @Deprecated
public static boolean isPotentialEmergencyNumber(String number) {
return isPotentialEmergencyNumber(getDefaultVoiceSubId(), number);
}
@@ -1802,9 +1814,14 @@
* @return true if the number is in the list of emergency numbers
* listed in the RIL / SIM, *or* if the number starts with the
* same digits as any of those emergency numbers.
+ *
+ * @deprecated Please use {@link TelephonyManager#isCurrentPotentialEmergencyNumber(String)}
+ * instead.
+ *
* @hide
*/
@UnsupportedAppUsage
+ @Deprecated
public static boolean isPotentialEmergencyNumber(int subId, String number) {
// Check against the emergency numbers listed by the RIL / SIM,
// and *don't* require an exact match.
@@ -1867,8 +1884,12 @@
* @return if the number is an emergency number for the specific country, then return true,
* otherwise false
*
+ * @deprecated Please use {@link TelephonyManager#isCurrentEmergencyNumber(String)}
+ * instead.
+ *
* @hide
*/
+ @Deprecated
@UnsupportedAppUsage
public static boolean isEmergencyNumber(String number, String defaultCountryIso) {
return isEmergencyNumber(getDefaultVoiceSubId(), number, defaultCountryIso);
@@ -1882,8 +1903,13 @@
* @param defaultCountryIso the specific country which the number should be checked against
* @return if the number is an emergency number for the specific country, then return true,
* otherwise false
+ *
+ * @deprecated Please use {@link TelephonyManager#isCurrentEmergencyNumber(String)}
+ * instead.
+ *
* @hide
*/
+ @Deprecated
public static boolean isEmergencyNumber(int subId, String number, String defaultCountryIso) {
return isEmergencyNumberInternal(subId, number,
defaultCountryIso,
@@ -1909,8 +1935,12 @@
* country, *or* if the number starts with the same digits as
* any of those emergency numbers.
*
+ * @deprecated Please use {@link TelephonyManager#isCurrentPotentialEmergencyNumber(String)}
+ * instead.
+ *
* @hide
*/
+ @Deprecated
public static boolean isPotentialEmergencyNumber(String number, String defaultCountryIso) {
return isPotentialEmergencyNumber(getDefaultVoiceSubId(), number, defaultCountryIso);
}
@@ -1934,8 +1964,13 @@
* @return true if the number is an emergency number for the specific
* country, *or* if the number starts with the same digits as
* any of those emergency numbers.
+ *
+ * @deprecated Please use {@link TelephonyManager#isCurrentPotentialEmergencyNumber(String)}
+ * instead.
+ *
* @hide
*/
+ @Deprecated
public static boolean isPotentialEmergencyNumber(int subId, String number,
String defaultCountryIso) {
return isEmergencyNumberInternal(subId, number,
@@ -1983,92 +2018,7 @@
private static boolean isEmergencyNumberInternal(int subId, String number,
String defaultCountryIso,
boolean useExactMatch) {
- // If the number passed in is null, just return false:
- if (number == null) return false;
-
- // If the number passed in is a SIP address, return false, since the
- // concept of "emergency numbers" is only meaningful for calls placed
- // over the cell network.
- // (Be sure to do this check *before* calling extractNetworkPortionAlt(),
- // since the whole point of extractNetworkPortionAlt() is to filter out
- // any non-dialable characters (which would turn 'abc911def@example.com'
- // into '911', for example.))
- if (isUriNumber(number)) {
- return false;
- }
-
- // Strip the separators from the number before comparing it
- // to the list.
- number = extractNetworkPortionAlt(number);
-
- String emergencyNumbers = "";
- int slotId = SubscriptionManager.getSlotIndex(subId);
-
- // retrieve the list of emergency numbers
- // check read-write ecclist property first
- String ecclist = (slotId <= 0) ? "ril.ecclist" : ("ril.ecclist" + slotId);
-
- emergencyNumbers = SystemProperties.get(ecclist, "");
-
- Rlog.d(LOG_TAG, "slotId:" + slotId + " subId:" + subId + " country:"
- + defaultCountryIso + " emergencyNumbers: " + emergencyNumbers);
-
- if (TextUtils.isEmpty(emergencyNumbers)) {
- // then read-only ecclist property since old RIL only uses this
- emergencyNumbers = SystemProperties.get("ro.ril.ecclist");
- }
-
- if (!TextUtils.isEmpty(emergencyNumbers)) {
- // searches through the comma-separated list for a match,
- // return true if one is found.
- for (String emergencyNum : emergencyNumbers.split(",")) {
- // It is not possible to append additional digits to an emergency number to dial
- // the number in Brazil - it won't connect.
- if (useExactMatch || "BR".equalsIgnoreCase(defaultCountryIso)) {
- if (number.equals(emergencyNum)) {
- return true;
- }
- } else {
- if (number.startsWith(emergencyNum)) {
- return true;
- }
- }
- }
- // no matches found against the list!
- return false;
- }
-
- Rlog.d(LOG_TAG, "System property doesn't provide any emergency numbers."
- + " Use embedded logic for determining ones.");
-
- // If slot id is invalid, means that there is no sim card.
- // According spec 3GPP TS22.101, the following numbers should be
- // ECC numbers when SIM/USIM is not present.
- emergencyNumbers = ((slotId < 0) ? "112,911,000,08,110,118,119,999" : "112,911");
-
- for (String emergencyNum : emergencyNumbers.split(",")) {
- if (useExactMatch) {
- if (number.equals(emergencyNum)) {
- return true;
- }
- } else {
- if (number.startsWith(emergencyNum)) {
- return true;
- }
- }
- }
-
- // No ecclist system property, so use our own list.
- if (defaultCountryIso != null) {
- ShortNumberInfo info = ShortNumberInfo.getInstance();
- if (useExactMatch) {
- return info.isEmergencyNumber(number, defaultCountryIso);
- } else {
- return info.connectsToEmergencyNumber(number, defaultCountryIso);
- }
- }
-
- return false;
+ return TelephonyManager.getDefault().isCurrentEmergencyNumber(number);
}
/**
@@ -2078,7 +2028,11 @@
* @param context the specific context which the number should be checked against
* @return true if the specified number is an emergency number for the country the user
* is currently in.
+ *
+ * @deprecated Please use {@link TelephonyManager#isCurrentEmergencyNumber(String)}
+ * instead.
*/
+ @Deprecated
public static boolean isLocalEmergencyNumber(Context context, String number) {
return isLocalEmergencyNumber(context, getDefaultVoiceSubId(), number);
}
@@ -2091,8 +2045,13 @@
* @param context the specific context which the number should be checked against
* @return true if the specified number is an emergency number for the country the user
* is currently in.
+ *
+ * @deprecated Please use {@link TelephonyManager#isCurrentEmergencyNumber(String)}
+ * instead.
+ *
* @hide
*/
+ @Deprecated
@UnsupportedAppUsage
public static boolean isLocalEmergencyNumber(Context context, int subId, String number) {
return isLocalEmergencyNumberInternal(subId, number,
@@ -2120,8 +2079,13 @@
* CountryDetector.
*
* @see android.location.CountryDetector
+ *
+ * @deprecated Please use {@link TelephonyManager#isCurrentPotentialEmergencyNumber(String)}
+ * instead.
+ *
* @hide
*/
+ @Deprecated
@UnsupportedAppUsage
public static boolean isPotentialLocalEmergencyNumber(Context context, String number) {
return isPotentialLocalEmergencyNumber(context, getDefaultVoiceSubId(), number);
@@ -2147,9 +2111,13 @@
* @return true if the specified number is an emergency number for a local country, based on the
* CountryDetector.
*
+ * @deprecated Please use {@link TelephonyManager#isCurrentPotentialEmergencyNumber(String)}
+ * instead.
+ *
* @hide
*/
@UnsupportedAppUsage
+ @Deprecated
public static boolean isPotentialLocalEmergencyNumber(Context context, int subId,
String number) {
return isLocalEmergencyNumberInternal(subId, number,
@@ -2217,6 +2185,101 @@
}
/**
+ * Back-up old logics for {@link #isEmergencyNumberInternal} for legacy and deprecate purpose.
+ *
+ * @hide
+ */
+ public static boolean isEmergencyNumberInternal(String number, boolean useExactMatch,
+ String defaultCountryIso) {
+ // If the number passed in is null, just return false:
+ if (number == null) return false;
+
+ // If the number passed in is a SIP address, return false, since the
+ // concept of "emergency numbers" is only meaningful for calls placed
+ // over the cell network.
+ // (Be sure to do this check *before* calling extractNetworkPortionAlt(),
+ // since the whole point of extractNetworkPortionAlt() is to filter out
+ // any non-dialable characters (which would turn 'abc911def@example.com'
+ // into '911', for example.))
+ if (PhoneNumberUtils.isUriNumber(number)) {
+ return false;
+ }
+
+ // Strip the separators from the number before comparing it
+ // to the list.
+ number = PhoneNumberUtils.extractNetworkPortionAlt(number);
+
+ String emergencyNumbers = "";
+ int slotId = SubscriptionManager.getSlotIndex(getDefaultVoiceSubId());
+
+ // retrieve the list of emergency numbers
+ // check read-write ecclist property first
+ String ecclist = (slotId <= 0) ? "ril.ecclist" : ("ril.ecclist" + slotId);
+
+ emergencyNumbers = SystemProperties.get(ecclist, "");
+
+ Rlog.d(LOG_TAG, "slotId:" + slotId + " country:"
+ + defaultCountryIso + " emergencyNumbers: " + emergencyNumbers);
+
+ if (TextUtils.isEmpty(emergencyNumbers)) {
+ // then read-only ecclist property since old RIL only uses this
+ emergencyNumbers = SystemProperties.get("ro.ril.ecclist");
+ }
+
+ if (!TextUtils.isEmpty(emergencyNumbers)) {
+ // searches through the comma-separated list for a match,
+ // return true if one is found.
+ for (String emergencyNum : emergencyNumbers.split(",")) {
+ // It is not possible to append additional digits to an emergency number to dial
+ // the number in Brazil - it won't connect.
+ if (useExactMatch || "BR".equalsIgnoreCase(defaultCountryIso)) {
+ if (number.equals(emergencyNum)) {
+ return true;
+ }
+ } else {
+ if (number.startsWith(emergencyNum)) {
+ return true;
+ }
+ }
+ }
+ // no matches found against the list!
+ return false;
+ }
+
+ Rlog.d(LOG_TAG, "System property doesn't provide any emergency numbers."
+ + " Use embedded logic for determining ones.");
+
+ // If slot id is invalid, means that there is no sim card.
+ // According spec 3GPP TS22.101, the following numbers should be
+ // ECC numbers when SIM/USIM is not present.
+ emergencyNumbers = ((slotId < 0) ? "112,911,000,08,110,118,119,999" : "112,911");
+
+ for (String emergencyNum : emergencyNumbers.split(",")) {
+ if (useExactMatch) {
+ if (number.equals(emergencyNum)) {
+ return true;
+ }
+ } else {
+ if (number.startsWith(emergencyNum)) {
+ return true;
+ }
+ }
+ }
+
+ // No ecclist system property, so use our own list.
+ if (defaultCountryIso != null) {
+ ShortNumberInfo info = ShortNumberInfo.getInstance();
+ if (useExactMatch) {
+ return info.isEmergencyNumber(number, defaultCountryIso);
+ } else {
+ return info.connectsToEmergencyNumber(number, defaultCountryIso);
+ }
+ }
+
+ return false;
+ }
+
+ /**
* isVoiceMailNumber: checks a given number against the voicemail
* number provided by the RIL and SIM card. The caller must have
* the READ_PHONE_STATE credential.
diff --git a/telephony/java/android/telephony/PhoneStateListener.java b/telephony/java/android/telephony/PhoneStateListener.java
index e8a28ca..0df0daf 100644
--- a/telephony/java/android/telephony/PhoneStateListener.java
+++ b/telephony/java/android/telephony/PhoneStateListener.java
@@ -27,12 +27,14 @@
import android.os.Handler;
import android.os.HandlerExecutor;
import android.os.Looper;
+import android.telephony.emergency.EmergencyNumber;
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.telephony.IPhoneStateListener;
import java.lang.ref.WeakReference;
import java.util.List;
+import java.util.Map;
import java.util.concurrent.Executor;
/**
@@ -313,6 +315,8 @@
*
* <p>Requires permission {@link android.Manifest.permission#READ_PHONE_STATE} or the calling
* app has carrier privileges (see {@link TelephonyManager#hasCarrierPrivileges}).
+ *
+ * @see #onEmergencyNumberListChanged
*/
public static final int LISTEN_EMERGENCY_NUMBER_LIST = 0x01000000;
@@ -603,6 +607,21 @@
}
/**
+ * Callback invoked when the current emergency number list has changed
+ *
+ * @param emergencyNumberList Map including the key as the active subscription ID
+ * (Note: if there is no active subscription, the key is
+ * {@link SubscriptionManager#getDefaultSubscriptionId})
+ * and the value as the list of {@link EmergencyNumber};
+ * null if this information is not available.
+ * @hide
+ */
+ public void onEmergencyNumberListChanged(
+ @NonNull Map<Integer, List<EmergencyNumber>> emergencyNumberList) {
+ // default implementation empty
+ }
+
+ /**
* Callback invoked when OEM hook raw event is received. Requires
* the READ_PRIVILEGED_PHONE_STATE permission.
* @param rawData is the byte array of the OEM hook raw data.
@@ -859,6 +878,16 @@
() -> psl.onPhysicalChannelConfigurationChanged(configs)));
}
+ @Override
+ public void onEmergencyNumberListChanged(Map emergencyNumberList) {
+ PhoneStateListener psl = mPhoneStateListenerWeakRef.get();
+ if (psl == null) return;
+
+ Binder.withCleanCallingIdentity(
+ () -> mExecutor.execute(
+ () -> psl.onEmergencyNumberListChanged(emergencyNumberList)));
+ }
+
public void onPhoneCapabilityChanged(PhoneCapability capability) {
PhoneStateListener psl = mPhoneStateListenerWeakRef.get();
if (psl == null) return;
diff --git a/telephony/java/android/telephony/ServiceState.java b/telephony/java/android/telephony/ServiceState.java
index ca0c854a..78f05168 100644
--- a/telephony/java/android/telephony/ServiceState.java
+++ b/telephony/java/android/telephony/ServiceState.java
@@ -27,6 +27,7 @@
import android.os.Parcelable;
import android.telephony.AccessNetworkConstants.AccessNetworkType;
import android.telephony.NetworkRegistrationState.Domain;
+import android.telephony.NetworkRegistrationState.NRStatus;
import android.text.TextUtils;
import java.lang.annotation.Retention;
@@ -1358,6 +1359,18 @@
}
/**
+ * Get the NR 5G status of the mobile data network.
+ * @return the NR 5G status.
+ * @hide
+ */
+ public @NRStatus int getNrStatus() {
+ final NetworkRegistrationState regState = getNetworkRegistrationState(
+ NetworkRegistrationState.DOMAIN_PS, AccessNetworkConstants.TransportType.WWAN);
+ if (regState == null) return NetworkRegistrationState.NR_STATUS_NONE;
+ return regState.getNrStatus();
+ }
+
+ /**
* @param nrFrequencyRange the frequency range of 5G NR.
* @hide
*/
@@ -1410,47 +1423,49 @@
}
/** @hide */
- public static int rilRadioTechnologyToNetworkType(@RilRadioTechnology int rt) {
- switch(rt) {
- case ServiceState.RIL_RADIO_TECHNOLOGY_GPRS:
- return TelephonyManager.NETWORK_TYPE_GPRS;
- case ServiceState.RIL_RADIO_TECHNOLOGY_EDGE:
- return TelephonyManager.NETWORK_TYPE_EDGE;
- case ServiceState.RIL_RADIO_TECHNOLOGY_UMTS:
- return TelephonyManager.NETWORK_TYPE_UMTS;
- case ServiceState.RIL_RADIO_TECHNOLOGY_HSDPA:
- return TelephonyManager.NETWORK_TYPE_HSDPA;
- case ServiceState.RIL_RADIO_TECHNOLOGY_HSUPA:
- return TelephonyManager.NETWORK_TYPE_HSUPA;
- case ServiceState.RIL_RADIO_TECHNOLOGY_HSPA:
- return TelephonyManager.NETWORK_TYPE_HSPA;
- case ServiceState.RIL_RADIO_TECHNOLOGY_IS95A:
- case ServiceState.RIL_RADIO_TECHNOLOGY_IS95B:
- return TelephonyManager.NETWORK_TYPE_CDMA;
- case ServiceState.RIL_RADIO_TECHNOLOGY_1xRTT:
- return TelephonyManager.NETWORK_TYPE_1xRTT;
- case ServiceState.RIL_RADIO_TECHNOLOGY_EVDO_0:
- return TelephonyManager.NETWORK_TYPE_EVDO_0;
- case ServiceState.RIL_RADIO_TECHNOLOGY_EVDO_A:
- return TelephonyManager.NETWORK_TYPE_EVDO_A;
- case ServiceState.RIL_RADIO_TECHNOLOGY_EVDO_B:
- return TelephonyManager.NETWORK_TYPE_EVDO_B;
- case ServiceState.RIL_RADIO_TECHNOLOGY_EHRPD:
- return TelephonyManager.NETWORK_TYPE_EHRPD;
- case ServiceState.RIL_RADIO_TECHNOLOGY_LTE:
- return TelephonyManager.NETWORK_TYPE_LTE;
- case ServiceState.RIL_RADIO_TECHNOLOGY_HSPAP:
- return TelephonyManager.NETWORK_TYPE_HSPAP;
- case ServiceState.RIL_RADIO_TECHNOLOGY_GSM:
- return TelephonyManager.NETWORK_TYPE_GSM;
- case ServiceState.RIL_RADIO_TECHNOLOGY_TD_SCDMA:
- return TelephonyManager.NETWORK_TYPE_TD_SCDMA;
- case ServiceState.RIL_RADIO_TECHNOLOGY_IWLAN:
- return TelephonyManager.NETWORK_TYPE_IWLAN;
- case ServiceState.RIL_RADIO_TECHNOLOGY_LTE_CA:
- return TelephonyManager.NETWORK_TYPE_LTE_CA;
- default:
- return TelephonyManager.NETWORK_TYPE_UNKNOWN;
+ public static int rilRadioTechnologyToNetworkType(@RilRadioTechnology int rat) {
+ switch(rat) {
+ case ServiceState.RIL_RADIO_TECHNOLOGY_GPRS:
+ return TelephonyManager.NETWORK_TYPE_GPRS;
+ case ServiceState.RIL_RADIO_TECHNOLOGY_EDGE:
+ return TelephonyManager.NETWORK_TYPE_EDGE;
+ case ServiceState.RIL_RADIO_TECHNOLOGY_UMTS:
+ return TelephonyManager.NETWORK_TYPE_UMTS;
+ case ServiceState.RIL_RADIO_TECHNOLOGY_HSDPA:
+ return TelephonyManager.NETWORK_TYPE_HSDPA;
+ case ServiceState.RIL_RADIO_TECHNOLOGY_HSUPA:
+ return TelephonyManager.NETWORK_TYPE_HSUPA;
+ case ServiceState.RIL_RADIO_TECHNOLOGY_HSPA:
+ return TelephonyManager.NETWORK_TYPE_HSPA;
+ case ServiceState.RIL_RADIO_TECHNOLOGY_IS95A:
+ case ServiceState.RIL_RADIO_TECHNOLOGY_IS95B:
+ return TelephonyManager.NETWORK_TYPE_CDMA;
+ case ServiceState.RIL_RADIO_TECHNOLOGY_1xRTT:
+ return TelephonyManager.NETWORK_TYPE_1xRTT;
+ case ServiceState.RIL_RADIO_TECHNOLOGY_EVDO_0:
+ return TelephonyManager.NETWORK_TYPE_EVDO_0;
+ case ServiceState.RIL_RADIO_TECHNOLOGY_EVDO_A:
+ return TelephonyManager.NETWORK_TYPE_EVDO_A;
+ case ServiceState.RIL_RADIO_TECHNOLOGY_EVDO_B:
+ return TelephonyManager.NETWORK_TYPE_EVDO_B;
+ case ServiceState.RIL_RADIO_TECHNOLOGY_EHRPD:
+ return TelephonyManager.NETWORK_TYPE_EHRPD;
+ case ServiceState.RIL_RADIO_TECHNOLOGY_LTE:
+ return TelephonyManager.NETWORK_TYPE_LTE;
+ case ServiceState.RIL_RADIO_TECHNOLOGY_HSPAP:
+ return TelephonyManager.NETWORK_TYPE_HSPAP;
+ case ServiceState.RIL_RADIO_TECHNOLOGY_GSM:
+ return TelephonyManager.NETWORK_TYPE_GSM;
+ case ServiceState.RIL_RADIO_TECHNOLOGY_TD_SCDMA:
+ return TelephonyManager.NETWORK_TYPE_TD_SCDMA;
+ case ServiceState.RIL_RADIO_TECHNOLOGY_IWLAN:
+ return TelephonyManager.NETWORK_TYPE_IWLAN;
+ case ServiceState.RIL_RADIO_TECHNOLOGY_LTE_CA:
+ return TelephonyManager.NETWORK_TYPE_LTE_CA;
+ case ServiceState.RIL_RADIO_TECHNOLOGY_NR:
+ return TelephonyManager.NETWORK_TYPE_NR;
+ default:
+ return TelephonyManager.NETWORK_TYPE_UNKNOWN;
}
}
@@ -1531,7 +1546,6 @@
}
}
-
/** @hide */
@UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P)
public @TelephonyManager.NetworkType int getDataNetworkType() {
diff --git a/telephony/java/android/telephony/TelephonyManager.java b/telephony/java/android/telephony/TelephonyManager.java
index fa9b76d..422e66d 100644
--- a/telephony/java/android/telephony/TelephonyManager.java
+++ b/telephony/java/android/telephony/TelephonyManager.java
@@ -810,6 +810,7 @@
* @see TelephonyManager#NETWORK_TYPE_LTE
* @see TelephonyManager#NETWORK_TYPE_EHRPD
* @see TelephonyManager#NETWORK_TYPE_HSPAP
+ * @see TelephonyManager#NETWORK_TYPE_NR
*
* <p class="note">
* Retrieve with
@@ -2328,6 +2329,7 @@
* @see #NETWORK_TYPE_LTE
* @see #NETWORK_TYPE_EHRPD
* @see #NETWORK_TYPE_HSPAP
+ * @see #NETWORK_TYPE_NR
*
* @hide
*/
@@ -2379,6 +2381,7 @@
* @see #NETWORK_TYPE_LTE
* @see #NETWORK_TYPE_EHRPD
* @see #NETWORK_TYPE_HSPAP
+ * @see #NETWORK_TYPE_NR
*/
@SuppressAutoDoc // Blocked by b/72967236 - no support for carrier privileges
@RequiresPermission(android.Manifest.permission.READ_PHONE_STATE)
@@ -2565,6 +2568,8 @@
return "IWLAN";
case NETWORK_TYPE_LTE_CA:
return "LTE_CA";
+ case NETWORK_TYPE_NR:
+ return "NR";
default:
return "UNKNOWN";
}
@@ -9449,8 +9454,13 @@
/**
* Get the emergency number list based on current locale, sim, default, modem and network.
*
- * <p>The emergency number {@link EmergencyNumber} with higher display priority is located at
- * the smaller index in the returned list.
+ * <p>In each returned list, the emergency number {@link EmergencyNumber} coming from higher
+ * priority sources will be located at the smaller index; the priority order of sources are:
+ * {@link EmergencyNumber#EMERGENCY_NUMBER_SOURCE_NETWORK_SIGNALING} >
+ * {@link EmergencyNumber#EMERGENCY_NUMBER_SOURCE_SIM} >
+ * {@link EmergencyNumber#EMERGENCY_NUMBER_SOURCE_DATABASE} >
+ * {@link EmergencyNumber#EMERGENCY_NUMBER_SOURCE_DEFAULT} >
+ * {@link EmergencyNumber#EMERGENCY_NUMBER_SOURCE_MODEM_CONFIG}
*
* <p>The subscriptions which the returned list would be based on, are all the active
* subscriptions, no matter which subscription could be used to create TelephonyManager.
@@ -9459,8 +9469,9 @@
* app has carrier privileges (see {@link #hasCarrierPrivileges}).
*
* @return Map including the key as the active subscription ID (Note: if there is no active
- * subscription, the key is {@link SubscriptionManager#DEFAULT_SUBSCRIPTION_ID}) and the value
- * as the list of {@link EmergencyNumber}; null if this information is not available.
+ * subscription, the key is {@link SubscriptionManager#getDefaultSubscriptionId}) and the value
+ * as the list of {@link EmergencyNumber}; null if this information is not available; or throw
+ * a SecurityException if the caller does not have the permission.
*/
@RequiresPermission(android.Manifest.permission.READ_PHONE_STATE)
@Nullable
@@ -9481,8 +9492,13 @@
* Get the per-category emergency number list based on current locale, sim, default, modem
* and network.
*
- * <p>The emergency number {@link EmergencyNumber} with higher display priority is located at
- * the smaller index in the returned list.
+ * <p>In each returned list, the emergency number {@link EmergencyNumber} coming from higher
+ * priority sources will be located at the smaller index; the priority order of sources are:
+ * {@link EmergencyNumber#EMERGENCY_NUMBER_SOURCE_NETWORK_SIGNALING} >
+ * {@link EmergencyNumber#EMERGENCY_NUMBER_SOURCE_SIM} >
+ * {@link EmergencyNumber#EMERGENCY_NUMBER_SOURCE_DATABASE} >
+ * {@link EmergencyNumber#EMERGENCY_NUMBER_SOURCE_DEFAULT} >
+ * {@link EmergencyNumber#EMERGENCY_NUMBER_SOURCE_MODEM_CONFIG}
*
* <p>The subscriptions which the returned list would be based on, are all the active
* subscriptions, no matter which subscription could be used to create TelephonyManager.
@@ -9503,8 +9519,9 @@
* <li>{@link EmergencyNumber#EMERGENCY_SERVICE_CATEGORY_AIEC} </li>
* </ol>
* @return Map including the key as the active subscription ID (Note: if there is no active
- * subscription, the key is {@link SubscriptionManager#DEFAULT_SUBSCRIPTION_ID}) and the value
- * as the list of {@link EmergencyNumber}; null if this information is not available.
+ * subscription, the key is {@link SubscriptionManager#getDefaultSubscriptionId}) and the value
+ * as the list of {@link EmergencyNumber}; null if this information is not available; or throw
+ * a SecurityException if the caller does not have the permission.
*/
@RequiresPermission(android.Manifest.permission.READ_PHONE_STATE)
@Nullable
@@ -9551,7 +9568,44 @@
if (telephony == null) {
return false;
}
- return telephony.isCurrentEmergencyNumber(number);
+ return telephony.isCurrentEmergencyNumber(number, true);
+ } catch (RemoteException ex) {
+ Log.e(TAG, "isCurrentEmergencyNumber RemoteException", ex);
+ }
+ return false;
+ }
+
+ /**
+ * Checks if the supplied number is an emergency number based on current locale, sim, default,
+ * modem and network.
+ *
+ * <p> Specifically, this method will return {@code true} if the specified number is an
+ * emergency number, *or* if the number simply starts with the same digits as any current
+ * emergency number.
+ *
+ * <p>The subscriptions which the identification would be based on, are all the active
+ * subscriptions, no matter which subscription could be used to create TelephonyManager.
+ *
+ * <p>Requires permission: {@link android.Manifest.permission#READ_PRIVILEGED_PHONE_STATE} or
+ * that the calling app has carrier privileges (see {@link #hasCarrierPrivileges}).
+ *
+ * @param number - the number to look up
+ * @return {@code true} if the given number is an emergency number or it simply starts with
+ * the same digits of any current emergency number based on current locale, sim, modem and
+ * network; {@code false} if it is not; or throw an SecurityException if the caller does not
+ * have the required permission/privileges
+ *
+ * @hide
+ */
+ @SystemApi
+ @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE)
+ public boolean isCurrentPotentialEmergencyNumber(@NonNull String number) {
+ try {
+ ITelephony telephony = getITelephony();
+ if (telephony == null) {
+ return false;
+ }
+ return telephony.isCurrentEmergencyNumber(number, false);
} catch (RemoteException ex) {
Log.e(TAG, "isCurrentEmergencyNumber RemoteException", ex);
}
diff --git a/telephony/java/android/telephony/emergency/EmergencyNumber.java b/telephony/java/android/telephony/emergency/EmergencyNumber.java
index 41f7bd7..fe062d5 100644
--- a/telephony/java/android/telephony/emergency/EmergencyNumber.java
+++ b/telephony/java/android/telephony/emergency/EmergencyNumber.java
@@ -22,6 +22,7 @@
import android.hardware.radio.V1_4.EmergencyServiceCategory;
import android.os.Parcel;
import android.os.Parcelable;
+import android.telephony.Rlog;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
@@ -150,6 +151,7 @@
@IntDef(flag = true, prefix = { "EMERGENCY_NUMBER_SOURCE_" }, value = {
EMERGENCY_NUMBER_SOURCE_NETWORK_SIGNALING,
EMERGENCY_NUMBER_SOURCE_SIM,
+ EMERGENCY_NUMBER_SOURCE_DATABASE,
EMERGENCY_NUMBER_SOURCE_MODEM_CONFIG,
EMERGENCY_NUMBER_SOURCE_DEFAULT
})
@@ -169,6 +171,10 @@
* Reference: 3gpp 22.101, Section 10 - Emergency Calls
*/
public static final int EMERGENCY_NUMBER_SOURCE_SIM = EmergencyNumberSource.SIM;
+ /**
+ * Bit-field which indicates the number is from the platform-maintained database.
+ */
+ public static final int EMERGENCY_NUMBER_SOURCE_DATABASE = 1 << 4;
/** Bit-field which indicates the number is from the modem config. */
public static final int EMERGENCY_NUMBER_SOURCE_MODEM_CONFIG =
EmergencyNumberSource.MODEM_CONFIG;
@@ -187,21 +193,24 @@
EMERGENCY_NUMBER_SOURCE_SET = new HashSet<Integer>();
EMERGENCY_NUMBER_SOURCE_SET.add(EMERGENCY_NUMBER_SOURCE_NETWORK_SIGNALING);
EMERGENCY_NUMBER_SOURCE_SET.add(EMERGENCY_NUMBER_SOURCE_SIM);
+ EMERGENCY_NUMBER_SOURCE_SET.add(EMERGENCY_NUMBER_SOURCE_DATABASE);
EMERGENCY_NUMBER_SOURCE_SET.add(EMERGENCY_NUMBER_SOURCE_MODEM_CONFIG);
EMERGENCY_NUMBER_SOURCE_SET.add(EMERGENCY_NUMBER_SOURCE_DEFAULT);
}
private final String mNumber;
private final String mCountryIso;
+ private final String mMnc;
private final int mEmergencyServiceCategoryBitmask;
private final int mEmergencyNumberSourceBitmask;
/** @hide */
public EmergencyNumber(@NonNull String number, @NonNull String countryIso,
- int emergencyServiceCategories,
+ @NonNull String mnc, int emergencyServiceCategories,
int emergencyNumberSources) {
this.mNumber = number;
this.mCountryIso = countryIso;
+ this.mMnc = mnc;
this.mEmergencyServiceCategoryBitmask = emergencyServiceCategories;
this.mEmergencyNumberSourceBitmask = emergencyNumberSources;
}
@@ -210,6 +219,7 @@
public EmergencyNumber(Parcel source) {
mNumber = source.readString();
mCountryIso = source.readString();
+ mMnc = source.readString();
mEmergencyServiceCategoryBitmask = source.readInt();
mEmergencyNumberSourceBitmask = source.readInt();
}
@@ -236,6 +246,15 @@
}
/**
+ * Get the Mobile Network Code of the emergency number.
+ *
+ * @return the Mobile Network Code of the emergency number.
+ */
+ public String getMnc() {
+ return mMnc;
+ }
+
+ /**
* Returns the bitmask of emergency service categories of the emergency number.
*
* @return bitmask of the emergency service categories
@@ -338,6 +357,7 @@
public void writeToParcel(Parcel dest, int flags) {
dest.writeString(mNumber);
dest.writeString(mCountryIso);
+ dest.writeString(mMnc);
dest.writeInt(mEmergencyServiceCategoryBitmask);
dest.writeInt(mEmergencyNumberSourceBitmask);
}
@@ -350,10 +370,10 @@
@Override
public String toString() {
- return "EmergencyNumber = " + "[Number]" + mNumber + " / [CountryIso]" + mCountryIso
- + " / [ServiceCategories]"
- + Integer.toBinaryString(mEmergencyServiceCategoryBitmask)
- + " / [Sources]" + Integer.toBinaryString(mEmergencyNumberSourceBitmask);
+ return "EmergencyNumber:" + "Number-" + mNumber + "|CountryIso-" + mCountryIso
+ + "|Mnc-" + mMnc
+ + "|ServiceCategories-" + Integer.toBinaryString(mEmergencyServiceCategoryBitmask)
+ + "|Sources-" + Integer.toBinaryString(mEmergencyNumberSourceBitmask);
}
@Override
@@ -373,6 +393,7 @@
* The priority of sources are defined as follows:
* EMERGENCY_NUMBER_SOURCE_NETWORK_SIGNALING >
* EMERGENCY_NUMBER_SOURCE_SIM >
+ * EMERGENCY_NUMBER_SOURCE_DATABASE >
* EMERGENCY_NUMBER_SOURCE_DEFAULT >
* EMERGENCY_NUMBER_SOURCE_MODEM_CONFIG
*
@@ -385,7 +406,9 @@
if (this.isFromSources(EMERGENCY_NUMBER_SOURCE_SIM)) {
score += 1 << 3;
}
- // TODO add a score if the number comes from Google's emergency number database
+ if (this.isFromSources(EMERGENCY_NUMBER_SOURCE_DATABASE)) {
+ score += 1 << 2;
+ }
if (this.isFromSources(EMERGENCY_NUMBER_SOURCE_DEFAULT)) {
score += 1 << 1;
}
@@ -412,14 +435,104 @@
< emergencyNumber.getDisplayPriorityScore()) {
return 1;
} else {
- /**
- * TODO if both numbers have the same display priority score, the number matches the
- * Google's emergency number database has a higher display priority.
- */
return 0;
}
}
+ /**
+ * In-place merge same emergency numbers in the emergency number list.
+ *
+ * A unique EmergencyNumber has a unique combination of ‘number’, ‘mcc’, 'mnc' and
+ * 'categories' fields. Multiple Emergency Number Sources should be merged into one bitfield
+ * for the same EmergencyNumber.
+ *
+ * @param emergencyNumberList the emergency number list to process
+ *
+ * @hide
+ */
+ public static void mergeSameNumbersInEmergencyNumberList(
+ List<EmergencyNumber> emergencyNumberList) {
+ if (emergencyNumberList == null) {
+ return;
+ }
+ Set<EmergencyNumber> mergedEmergencyNumber = new HashSet<>();
+ for (int i = 0; i < emergencyNumberList.size(); i++) {
+ // Skip the check because it was merged.
+ if (mergedEmergencyNumber.contains(emergencyNumberList.get(i))) {
+ continue;
+ }
+ for (int j = i + 1; j < emergencyNumberList.size(); j++) {
+ if (isSameEmergencyNumber(
+ emergencyNumberList.get(i), emergencyNumberList.get(j))) {
+ Rlog.e(LOG_TAG, "Found unexpected duplicate numbers: "
+ + emergencyNumberList.get(i) + " vs " + emergencyNumberList.get(j));
+ // Set the merged emergency number in the current position
+ emergencyNumberList.set(i, mergeNumbers(
+ emergencyNumberList.get(i), emergencyNumberList.get(j)));
+ // Mark the emergency number has been merged
+ mergedEmergencyNumber.add(emergencyNumberList.get(j));
+ }
+ }
+ }
+ // Remove the marked emergency number in the orignal list
+ for (int i = 0; i < emergencyNumberList.size(); i++) {
+ if (mergedEmergencyNumber.contains(emergencyNumberList.get(i))) {
+ emergencyNumberList.remove(i--);
+ }
+ }
+ }
+
+ /**
+ * Check if two emergency numbers are the same.
+ *
+ * A unique EmergencyNumber has a unique combination of ‘number’, ‘mcc’, 'mnc' and
+ * 'categories' fields. Multiple Emergency Number Sources should be merged into one bitfield
+ * for the same EmergencyNumber.
+ *
+ * @param first first EmergencyNumber to compare
+ * @param second second EmergencyNumber to compare
+ * @return true if they are the same EmergencyNumbers; false otherwise.
+ *
+ * @hide
+ */
+ public static boolean isSameEmergencyNumber(@NonNull EmergencyNumber first,
+ @NonNull EmergencyNumber second) {
+ if (!first.getNumber().equals(second.getNumber())) {
+ return false;
+ }
+ if (!first.getCountryIso().equals(second.getCountryIso())) {
+ return false;
+ }
+ if (!first.getMnc().equals(second.getMnc())) {
+ return false;
+ }
+ if (first.getEmergencyServiceCategoryBitmask()
+ != second.getEmergencyServiceCategoryBitmask()) {
+ return false;
+ }
+ return true;
+ }
+
+ /**
+ * Get a merged EmergencyNumber for two numbers if they are the same.
+ *
+ * @param first first EmergencyNumber to compare
+ * @param second second EmergencyNumber to compare
+ * @return a merged EmergencyNumber or null if they are not the same EmergencyNumber
+ *
+ * @hide
+ */
+ public static EmergencyNumber mergeNumbers(@NonNull EmergencyNumber first,
+ @NonNull EmergencyNumber second) {
+ if (isSameEmergencyNumber(first, second)) {
+ return new EmergencyNumber(first.getNumber(), first.getCountryIso(), first.getMnc(),
+ first.getEmergencyServiceCategoryBitmask(),
+ first.getEmergencyNumberSourceBitmask()
+ | second.getEmergencyNumberSourceBitmask());
+ }
+ return null;
+ }
+
public static final Parcelable.Creator<EmergencyNumber> CREATOR =
new Parcelable.Creator<EmergencyNumber>() {
@Override
diff --git a/telephony/java/com/android/internal/telephony/IPhoneStateListener.aidl b/telephony/java/com/android/internal/telephony/IPhoneStateListener.aidl
index 79f0635..78fc0bc4 100644
--- a/telephony/java/com/android/internal/telephony/IPhoneStateListener.aidl
+++ b/telephony/java/com/android/internal/telephony/IPhoneStateListener.aidl
@@ -25,6 +25,7 @@
import android.telephony.PhysicalChannelConfig;
import android.telephony.PreciseCallState;
import android.telephony.PreciseDataConnectionState;
+import android.telephony.emergency.EmergencyNumber;
oneway interface IPhoneStateListener {
void onServiceStateChanged(in ServiceState serviceState);
@@ -53,5 +54,6 @@
void onPhoneCapabilityChanged(in PhoneCapability capability);
void onPreferredDataSubIdChanged(in int subId);
void onRadioPowerStateChanged(in int state);
+ void onEmergencyNumberListChanged(in Map emergencyNumberList);
}
diff --git a/telephony/java/com/android/internal/telephony/ITelephony.aidl b/telephony/java/com/android/internal/telephony/ITelephony.aidl
index 399dc52..88b9302 100644
--- a/telephony/java/com/android/internal/telephony/ITelephony.aidl
+++ b/telephony/java/com/android/internal/telephony/ITelephony.aidl
@@ -1716,7 +1716,7 @@
/**
* Identify if the number is emergency number, based on all the active subscriptions.
*/
- boolean isCurrentEmergencyNumber(String number);
+ boolean isCurrentEmergencyNumber(String number, boolean exactMatch);
/**
* Return a list of certs in hex string from loaded carrier privileges access rules.
diff --git a/telephony/java/com/android/internal/telephony/ITelephonyRegistry.aidl b/telephony/java/com/android/internal/telephony/ITelephonyRegistry.aidl
index 76e7509..d9f5c3f 100644
--- a/telephony/java/com/android/internal/telephony/ITelephonyRegistry.aidl
+++ b/telephony/java/com/android/internal/telephony/ITelephonyRegistry.aidl
@@ -81,5 +81,5 @@
void notifyPhoneCapabilityChanged(in PhoneCapability capability);
void notifyPreferredDataSubIdChanged(int preferredSubId);
void notifyRadioPowerStateChanged(in int state);
- void notifyEmergencyNumberList(in List<EmergencyNumber> emergencyNumberList);
+ void notifyEmergencyNumberList();
}
diff --git a/telephony/java/com/android/internal/telephony/RILConstants.java b/telephony/java/com/android/internal/telephony/RILConstants.java
index cb8269e..c934317 100644
--- a/telephony/java/com/android/internal/telephony/RILConstants.java
+++ b/telephony/java/com/android/internal/telephony/RILConstants.java
@@ -483,4 +483,5 @@
int RIL_UNSOL_HAL_NON_RIL_BASE = 1100;
int RIL_UNSOL_ICC_SLOT_STATUS = 1100;
int RIL_UNSOL_PHYSICAL_CHANNEL_CONFIG = 1101;
+ int RIL_UNSOL_EMERGENCY_NUMBER_LIST = 1102;
}
diff --git a/test-mock/src/android/test/mock/MockContentProvider.java b/test-mock/src/android/test/mock/MockContentProvider.java
index b917fbd..0ac35bc 100644
--- a/test-mock/src/android/test/mock/MockContentProvider.java
+++ b/test-mock/src/android/test/mock/MockContentProvider.java
@@ -54,10 +54,10 @@
*/
private class InversionIContentProvider implements IContentProvider {
@Override
- public ContentProviderResult[] applyBatch(String callingPackage,
+ public ContentProviderResult[] applyBatch(String callingPackage, String authority,
ArrayList<ContentProviderOperation> operations)
throws RemoteException, OperationApplicationException {
- return MockContentProvider.this.applyBatch(operations);
+ return MockContentProvider.this.applyBatch(authority, operations);
}
@Override
@@ -112,9 +112,9 @@
}
@Override
- public Bundle call(String callingPackage, String method, String request, Bundle args)
- throws RemoteException {
- return MockContentProvider.this.call(method, request, args);
+ public Bundle call(String callingPackage, String authority, String method, String request,
+ Bundle args) throws RemoteException {
+ return MockContentProvider.this.call(authority, method, request, args);
}
@Override
diff --git a/test-mock/src/android/test/mock/MockIContentProvider.java b/test-mock/src/android/test/mock/MockIContentProvider.java
index 112d7ee..fc2a464 100644
--- a/test-mock/src/android/test/mock/MockIContentProvider.java
+++ b/test-mock/src/android/test/mock/MockIContentProvider.java
@@ -80,7 +80,7 @@
}
@Override
- public ContentProviderResult[] applyBatch(String callingPackage,
+ public ContentProviderResult[] applyBatch(String callingPackage, String authority,
ArrayList<ContentProviderOperation> operations) {
throw new UnsupportedOperationException("unimplemented mock method");
}
@@ -103,8 +103,8 @@
}
@Override
- public Bundle call(String callingPackage, String method, String request, Bundle args)
- throws RemoteException {
+ public Bundle call(String callingPackage, String authority, String method, String request,
+ Bundle args) throws RemoteException {
throw new UnsupportedOperationException("unimplemented mock method");
}
diff --git a/tests/FrameworkPerf/AndroidManifest.xml b/tests/FrameworkPerf/AndroidManifest.xml
index d62ef9e..ca25386 100644
--- a/tests/FrameworkPerf/AndroidManifest.xml
+++ b/tests/FrameworkPerf/AndroidManifest.xml
@@ -13,7 +13,8 @@
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
- <service android:name="SchedulerService">
+ <service android:name="SchedulerService"
+ android:foregroundServiceType="sync">
</service>
<service android:name="TestService" android:process=":test">
</service>
diff --git a/tests/FrameworkPerf/src/com/android/frameworkperf/SchedulerService.java b/tests/FrameworkPerf/src/com/android/frameworkperf/SchedulerService.java
index fc3f390..d4cbbf9 100644
--- a/tests/FrameworkPerf/src/com/android/frameworkperf/SchedulerService.java
+++ b/tests/FrameworkPerf/src/com/android/frameworkperf/SchedulerService.java
@@ -17,16 +17,22 @@
package com.android.frameworkperf;
import android.app.Notification;
+import android.app.NotificationChannel;
+import android.app.NotificationManager;
import android.app.PendingIntent;
import android.app.Service;
import android.content.Intent;
import android.os.IBinder;
public class SchedulerService extends Service {
+ private static final String NOTIFICATION_CHANNEL_ID = SchedulerService.class.getSimpleName();
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
- Notification status = new Notification.Builder(this)
+ getSystemService(NotificationManager.class).createNotificationChannel(
+ new NotificationChannel(NOTIFICATION_CHANNEL_ID, NOTIFICATION_CHANNEL_ID,
+ NotificationManager.IMPORTANCE_DEFAULT));
+ Notification status = new Notification.Builder(this, NOTIFICATION_CHANNEL_ID)
.setSmallIcon(R.drawable.stat_happy)
.setWhen(System.currentTimeMillis())
.setContentTitle("Scheduler Test running")
diff --git a/tests/net/Android.mk b/tests/net/Android.mk
index 132135d..9d1edbf 100644
--- a/tests/net/Android.mk
+++ b/tests/net/Android.mk
@@ -51,7 +51,6 @@
liblog \
liblzma \
libnativehelper \
- libnetdaidl \
libpackagelistparser \
libpcre2 \
libselinux \
@@ -93,7 +92,6 @@
liblog \
libcutils \
libnativehelper \
- libnetdaidl \
netd_aidl_interface-cpp
LOCAL_STATIC_LIBRARIES := \
diff --git a/tests/net/java/android/net/NetworkCapabilitiesTest.java b/tests/net/java/android/net/NetworkCapabilitiesTest.java
index b40921f..50aef1d 100644
--- a/tests/net/java/android/net/NetworkCapabilitiesTest.java
+++ b/tests/net/java/android/net/NetworkCapabilitiesTest.java
@@ -24,9 +24,9 @@
import static android.net.NetworkCapabilities.NET_CAPABILITY_MMS;
import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_METERED;
import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_RESTRICTED;
-import static android.net.NetworkCapabilities.NET_CAPABILITY_OEM_PAID;
import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_ROAMING;
import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_VPN;
+import static android.net.NetworkCapabilities.NET_CAPABILITY_OEM_PAID;
import static android.net.NetworkCapabilities.NET_CAPABILITY_VALIDATED;
import static android.net.NetworkCapabilities.NET_CAPABILITY_WIFI_P2P;
import static android.net.NetworkCapabilities.RESTRICTED_CAPABILITIES;
@@ -46,7 +46,6 @@
import android.test.suitebuilder.annotation.SmallTest;
import android.util.ArraySet;
-
import org.junit.Test;
import org.junit.runner.RunWith;
@@ -457,6 +456,62 @@
assertEquals(nc1, nc2);
}
+ @Test
+ public void testSetNetworkSpecifierOnMultiTransportNc() {
+ // Sequence 1: Transport + Transport + NetworkSpecifier
+ NetworkCapabilities nc1 = new NetworkCapabilities();
+ nc1.addTransportType(TRANSPORT_CELLULAR).addTransportType(TRANSPORT_WIFI);
+ try {
+ nc1.setNetworkSpecifier(new StringNetworkSpecifier("specs"));
+ fail("Cannot set NetworkSpecifier on a NetworkCapability with multiple transports!");
+ } catch (IllegalStateException expected) {
+ // empty
+ }
+
+ // Sequence 2: Transport + NetworkSpecifier + Transport
+ NetworkCapabilities nc2 = new NetworkCapabilities();
+ nc2.addTransportType(TRANSPORT_CELLULAR).setNetworkSpecifier(
+ new StringNetworkSpecifier("specs"));
+ try {
+ nc2.addTransportType(TRANSPORT_WIFI);
+ fail("Cannot set NetworkSpecifier on a NetworkCapability with multiple transports!");
+ } catch (IllegalStateException expected) {
+ // empty
+ }
+ }
+
+ @Test
+ public void testSetTransportInfoOnMultiTransportNc() {
+ // Sequence 1: Transport + Transport + TransportInfo
+ NetworkCapabilities nc1 = new NetworkCapabilities();
+ nc1.addTransportType(TRANSPORT_CELLULAR).addTransportType(TRANSPORT_WIFI)
+ .setTransportInfo(new TransportInfo() {});
+
+ // Sequence 2: Transport + NetworkSpecifier + Transport
+ NetworkCapabilities nc2 = new NetworkCapabilities();
+ nc2.addTransportType(TRANSPORT_CELLULAR).setTransportInfo(new TransportInfo() {})
+ .addTransportType(TRANSPORT_WIFI);
+ }
+
+ @Test
+ public void testCombineTransportInfo() {
+ NetworkCapabilities nc1 = new NetworkCapabilities();
+ nc1.setTransportInfo(new TransportInfo() {
+ // empty
+ });
+ NetworkCapabilities nc2 = new NetworkCapabilities();
+ nc2.setTransportInfo(new TransportInfo() {
+ // empty
+ });
+
+ try {
+ nc1.combineCapabilities(nc2);
+ fail("Should not be able to combine NetworkCaabilities which contain TransportInfos");
+ } catch (IllegalStateException expected) {
+ // empty
+ }
+ }
+
private void assertEqualsThroughMarshalling(NetworkCapabilities netCap) {
Parcel p = Parcel.obtain();
netCap.writeToParcel(p, /* flags */ 0);
diff --git a/tests/net/java/android/net/NetworkStatsTest.java b/tests/net/java/android/net/NetworkStatsTest.java
index d6dbf5a..1e3a49b 100644
--- a/tests/net/java/android/net/NetworkStatsTest.java
+++ b/tests/net/java/android/net/NetworkStatsTest.java
@@ -448,22 +448,58 @@
}
@Test
- public void testWithoutUid() throws Exception {
- final NetworkStats before = new NetworkStats(TEST_START, 3)
- .addValues(TEST_IFACE, 100, SET_DEFAULT, TAG_NONE, 128L, 8L, 0L, 2L, 20L)
- .addValues(TEST_IFACE2, 100, SET_DEFAULT, TAG_NONE, 512L, 32L, 0L, 0L, 0L)
- .addValues(TEST_IFACE2, 100, SET_DEFAULT, 0xF00D, 64L, 4L, 0L, 0L, 0L)
- .addValues(TEST_IFACE2, 100, SET_FOREGROUND, TAG_NONE, 512L, 32L, 0L, 0L, 0L)
- .addValues(TEST_IFACE, 101, SET_DEFAULT, TAG_NONE, 128L, 8L, 0L, 0L, 0L)
- .addValues(TEST_IFACE, 101, SET_DEFAULT, 0xF00D, 128L, 8L, 0L, 0L, 0L);
+ public void testRemoveUids() throws Exception {
+ final NetworkStats before = new NetworkStats(TEST_START, 3);
- final NetworkStats after = before.withoutUids(new int[] { 100 });
- assertEquals(6, before.size());
- assertEquals(2, after.size());
- assertValues(after, 0, TEST_IFACE, 101, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_NO,
- DEFAULT_NETWORK_NO, 128L, 8L, 0L, 0L, 0L);
- assertValues(after, 1, TEST_IFACE, 101, SET_DEFAULT, 0xF00D, METERED_NO, ROAMING_NO,
- DEFAULT_NETWORK_NO, 128L, 8L, 0L, 0L, 0L);
+ // Test 0 item stats.
+ NetworkStats after = before.clone();
+ after.removeUids(new int[0]);
+ assertEquals(0, after.size());
+ after.removeUids(new int[] {100});
+ assertEquals(0, after.size());
+
+ // Test 1 item stats.
+ before.addValues(TEST_IFACE, 99, SET_DEFAULT, TAG_NONE, 1L, 128L, 0L, 2L, 20L);
+ after = before.clone();
+ after.removeUids(new int[0]);
+ assertEquals(1, after.size());
+ assertValues(after, 0, TEST_IFACE, 99, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_NO,
+ DEFAULT_NETWORK_NO, 1L, 128L, 0L, 2L, 20L);
+ after.removeUids(new int[] {99});
+ assertEquals(0, after.size());
+
+ // Append remaining test items.
+ before.addValues(TEST_IFACE, 100, SET_DEFAULT, TAG_NONE, 2L, 64L, 0L, 2L, 20L)
+ .addValues(TEST_IFACE2, 100, SET_DEFAULT, TAG_NONE, 4L, 32L, 0L, 0L, 0L)
+ .addValues(TEST_IFACE2, 100, SET_DEFAULT, 0xF00D, 8L, 16L, 0L, 0L, 0L)
+ .addValues(TEST_IFACE2, 100, SET_FOREGROUND, TAG_NONE, 16L, 8L, 0L, 0L, 0L)
+ .addValues(TEST_IFACE, 101, SET_DEFAULT, TAG_NONE, 32L, 4L, 0L, 0L, 0L)
+ .addValues(TEST_IFACE, 101, SET_DEFAULT, 0xF00D, 64L, 2L, 0L, 0L, 0L);
+ assertEquals(7, before.size());
+
+ // Test remove with empty uid list.
+ after = before.clone();
+ after.removeUids(new int[0]);
+ assertValues(after.getTotalIncludingTags(null), 127L, 254L, 0L, 4L, 40L);
+
+ // Test remove uids don't exist in stats.
+ after.removeUids(new int[] {98, 0, Integer.MIN_VALUE, Integer.MAX_VALUE});
+ assertValues(after.getTotalIncludingTags(null), 127L, 254L, 0L, 4L, 40L);
+
+ // Test remove all uids.
+ after.removeUids(new int[] {99, 100, 100, 101});
+ assertEquals(0, after.size());
+
+ // Test remove in the middle.
+ after = before.clone();
+ after.removeUids(new int[] {100});
+ assertEquals(3, after.size());
+ assertValues(after, 0, TEST_IFACE, 99, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_NO,
+ DEFAULT_NETWORK_NO, 1L, 128L, 0L, 2L, 20L);
+ assertValues(after, 1, TEST_IFACE, 101, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_NO,
+ DEFAULT_NETWORK_NO, 32L, 4L, 0L, 0L, 0L);
+ assertValues(after, 2, TEST_IFACE, 101, SET_DEFAULT, 0xF00D, METERED_NO, ROAMING_NO,
+ DEFAULT_NETWORK_NO, 64L, 2L, 0L, 0L, 0L);
}
@Test
diff --git a/tests/net/java/android/net/ip/IpClientTest.java b/tests/net/java/android/net/ip/IpClientTest.java
index 5a8d2cd..cba3c65 100644
--- a/tests/net/java/android/net/ip/IpClientTest.java
+++ b/tests/net/java/android/net/ip/IpClientTest.java
@@ -81,7 +81,7 @@
private static final int TEST_IFINDEX = 1001;
// See RFC 7042#section-2.1.2 for EUI-48 documentation values.
private static final MacAddress TEST_MAC = MacAddress.fromString("00:00:5E:00:53:01");
- private static final int TEST_TIMEOUT_MS = 200;
+ private static final int TEST_TIMEOUT_MS = 400;
@Mock private Context mContext;
@Mock private INetworkManagementService mNMService;
diff --git a/tools/stats_log_api_gen/main.cpp b/tools/stats_log_api_gen/main.cpp
index 88b7e2e..5192a0e 100644
--- a/tools/stats_log_api_gen/main.cpp
+++ b/tools/stats_log_api_gen/main.cpp
@@ -264,6 +264,10 @@
chainField.name.c_str(), chainField.name.c_str());
}
}
+ } else if (*arg == JAVA_TYPE_BYTE_ARRAY) {
+ fprintf(out, ", %s arg%d, size_t arg%d_length",
+ cpp_type_name(*arg), argIndex, argIndex);
+
} else if (*arg == JAVA_TYPE_KEY_VALUE_PAIR) {
fprintf(out, ", const std::map<int, int32_t>& arg%d_1, "
"const std::map<int, int64_t>& arg%d_2, "
@@ -343,6 +347,10 @@
fprintf(out, " }\n");
fprintf(out, " event.end();\n\n");
+ } else if (*arg == JAVA_TYPE_BYTE_ARRAY) {
+ fprintf(out,
+ " event.AppendCharArray(arg%d, arg%d_length);\n",
+ argIndex, argIndex);
} else {
if (*arg == JAVA_TYPE_STRING) {
fprintf(out, " if (arg%d == NULL) {\n", argIndex);
@@ -383,12 +391,17 @@
chainField.name.c_str(), chainField.name.c_str());
}
}
+ } else if (*arg == JAVA_TYPE_BYTE_ARRAY) {
+ fprintf(out, ", %s arg%d, size_t arg%d_length",
+ cpp_type_name(*arg), argIndex, argIndex);
+
} else if (*arg == JAVA_TYPE_KEY_VALUE_PAIR) {
- fprintf(out, ", const std::map<int, int32_t>& arg%d_1, "
- "const std::map<int, int64_t>& arg%d_2, "
- "const std::map<int, char const*>& arg%d_3, "
- "const std::map<int, float>& arg%d_4",
- argIndex, argIndex, argIndex, argIndex);
+ fprintf(out,
+ ", const std::map<int, int32_t>& arg%d_1, "
+ "const std::map<int, int64_t>& arg%d_2, "
+ "const std::map<int, char const*>& arg%d_3, "
+ "const std::map<int, float>& arg%d_4",
+ argIndex, argIndex, argIndex, argIndex);
} else {
fprintf(out, ", %s arg%d", cpp_type_name(*arg), argIndex);
}
@@ -415,9 +428,11 @@
chainField.name.c_str(), chainField.name.c_str());
}
}
- } else if (*arg == JAVA_TYPE_KEY_VALUE_PAIR) {
- fprintf(out, ", arg%d_1, arg%d_2, arg%d_3, arg%d_4",
- argIndex, argIndex, argIndex, argIndex);
+ } else if (*arg == JAVA_TYPE_BYTE_ARRAY) {
+ fprintf(out, ", arg%d, arg%d_length", argIndex, argIndex);
+ } else if (*arg == JAVA_TYPE_KEY_VALUE_PAIR) {
+ fprintf(out, ", arg%d_1, arg%d_2, arg%d_3, arg%d_4", argIndex,
+ argIndex, argIndex, argIndex);
} else {
fprintf(out, ", arg%d", argIndex);
}
@@ -580,6 +595,11 @@
field->name.c_str(),
field->name.c_str(),
field->name.c_str());
+ } else if (field->javaType == JAVA_TYPE_BYTE_ARRAY) {
+ fprintf(out, ", %s %s, size_t %s_length",
+ cpp_type_name(field->javaType), field->name.c_str(),
+ field->name.c_str());
+
} else {
fprintf(out, ", %s %s", cpp_type_name(field->javaType), field->name.c_str());
}
@@ -613,6 +633,9 @@
"const std::map<int, char const*>& arg%d_3, "
"const std::map<int, float>& arg%d_4",
argIndex, argIndex, argIndex, argIndex);
+ } else if (*arg == JAVA_TYPE_BYTE_ARRAY) {
+ fprintf(out, ", %s arg%d, size_t arg%d_length",
+ cpp_type_name(*arg), argIndex, argIndex);
} else {
fprintf(out, ", %s arg%d", cpp_type_name(*arg), argIndex);
}
@@ -1128,6 +1151,7 @@
hadStringOrChain = true;
fprintf(out, " jbyte* jbyte_array%d;\n", argIndex);
fprintf(out, " const char* str%d;\n", argIndex);
+ fprintf(out, " int str%d_length = 0;\n", argIndex);
fprintf(out,
" if (arg%d != NULL && env->GetArrayLength(arg%d) > "
"0) {\n",
@@ -1137,6 +1161,9 @@
"env->GetByteArrayElements(arg%d, NULL);\n",
argIndex, argIndex);
fprintf(out,
+ " str%d_length = env->GetArrayLength(arg%d);\n",
+ argIndex, argIndex);
+ fprintf(out,
" str%d = "
"reinterpret_cast<char*>(env->GetByteArrayElements(arg%"
"d, NULL));\n",
@@ -1224,6 +1251,10 @@
? "str"
: "arg";
fprintf(out, ", (%s)%s%d", cpp_type_name(*arg), argName, argIndex);
+
+ if (*arg == JAVA_TYPE_BYTE_ARRAY) {
+ fprintf(out, ", %s%d_length", argName, argIndex);
+ }
}
argIndex++;
}