Merge "Revert "Enforce that a PendingIntent has an explicit mutability ...""
diff --git a/Android.bp b/Android.bp
index df0cf0b..1a73e9d 100644
--- a/Android.bp
+++ b/Android.bp
@@ -528,6 +528,7 @@
"android.hardware.vibrator-V1.1-java",
"android.hardware.vibrator-V1.2-java",
"android.hardware.vibrator-V1.3-java",
+ "android.security.apc-java",
"android.system.keystore2-java",
"android.system.suspend.control.internal-java",
"cameraprotosnano",
diff --git a/apct-tests/perftests/windowmanager/src/android/wm/WindowAddRemovePerfTest.java b/apct-tests/perftests/windowmanager/src/android/wm/WindowAddRemovePerfTest.java
index 9403e8b..c37f6d9 100644
--- a/apct-tests/perftests/windowmanager/src/android/wm/WindowAddRemovePerfTest.java
+++ b/apct-tests/perftests/windowmanager/src/android/wm/WindowAddRemovePerfTest.java
@@ -107,8 +107,8 @@
long startTime = SystemClock.elapsedRealtimeNanos();
session.addToDisplay(this, mLayoutParams, View.VISIBLE,
- Display.DEFAULT_DISPLAY, mRequestedVisibility, mOutFrame,
- mOutDisplayCutout, inputChannel, mOutInsetsState, mOutControls);
+ Display.DEFAULT_DISPLAY, mRequestedVisibility, mOutFrame, inputChannel,
+ mOutInsetsState, mOutControls);
final long elapsedTimeNsOfAdd = SystemClock.elapsedRealtimeNanos() - startTime;
state.addExtraResult("add", elapsedTimeNsOfAdd);
diff --git a/apex/appsearch/framework/java/android/app/appsearch/SearchResults.java b/apex/appsearch/framework/java/android/app/appsearch/SearchResults.java
index 05735cc..82c2d26 100644
--- a/apex/appsearch/framework/java/android/app/appsearch/SearchResults.java
+++ b/apex/appsearch/framework/java/android/app/appsearch/SearchResults.java
@@ -45,33 +45,35 @@
private final IAppSearchManager mService;
+ // The database name to search over. If null, this will search over all database names.
@Nullable
private final String mDatabaseName;
- @UserIdInt
- private final int mUserId;
-
private final String mQueryExpression;
private final SearchSpec mSearchSpec;
+ @UserIdInt
+ private final int mUserId;
+
private final Executor mExecutor;
private long mNextPageToken;
private boolean mIsFirstLoad = true;
- SearchResults(@NonNull IAppSearchManager service,
+ SearchResults(
+ @NonNull IAppSearchManager service,
@Nullable String databaseName,
@NonNull String queryExpression,
@NonNull SearchSpec searchSpec,
@UserIdInt int userId,
@NonNull @CallbackExecutor Executor executor) {
mService = Objects.requireNonNull(service);
- mUserId = userId;
- mDatabaseName = Objects.requireNonNull(databaseName);
+ mDatabaseName = databaseName;
mQueryExpression = Objects.requireNonNull(queryExpression);
mSearchSpec = Objects.requireNonNull(searchSpec);
+ mUserId = userId;
mExecutor = Objects.requireNonNull(executor);
}
@@ -90,11 +92,14 @@
if (mIsFirstLoad) {
mIsFirstLoad = false;
if (mDatabaseName == null) {
+ // Global query, there's no one package-database combination to check.
mService.globalQuery(mQueryExpression, mSearchSpec.getBundle(), mUserId,
wrapCallback(callback));
} else {
- mService.query(mDatabaseName, mQueryExpression, mSearchSpec.getBundle(),
- mUserId, wrapCallback(callback));
+ // Normal local query, pass in specified database.
+ mService.query(
+ mDatabaseName, mQueryExpression, mSearchSpec.getBundle(), mUserId,
+ wrapCallback(callback));
}
} else {
mService.getNextPage(mNextPageToken, mUserId, wrapCallback(callback));
@@ -104,6 +109,24 @@
}
}
+ @Override
+ public void close() {
+ try {
+ mService.invalidateNextPageToken(mNextPageToken, mUserId);
+ } catch (RemoteException e) {
+ Log.d(TAG, "Unable to close the SearchResults", e);
+ }
+ }
+
+ private IAppSearchResultCallback wrapCallback(
+ @NonNull Consumer<AppSearchResult<List<SearchResult>>> callback) {
+ return new IAppSearchResultCallback.Stub() {
+ public void onResult(AppSearchResult result) {
+ mExecutor.execute(() -> invokeCallback(result, callback));
+ }
+ };
+ }
+
private void invokeCallback(AppSearchResult result,
@NonNull Consumer<AppSearchResult<List<SearchResult>>> callback) {
if (result.isSuccess()) {
@@ -120,23 +143,4 @@
callback.accept(result);
}
}
- @Override
- public void close() {
- mExecutor.execute(() -> {
- try {
- mService.invalidateNextPageToken(mNextPageToken, mUserId);
- } catch (RemoteException e) {
- Log.d(TAG, "Unable to close the SearchResults", e);
- }
- });
- }
-
- private IAppSearchResultCallback wrapCallback(
- @NonNull Consumer<AppSearchResult<List<SearchResult>>> callback) {
- return new IAppSearchResultCallback.Stub() {
- public void onResult(AppSearchResult result) {
- mExecutor.execute(() -> invokeCallback(result, callback));
- }
- };
- }
}
diff --git a/apex/appsearch/framework/java/external/android/app/appsearch/SearchSpec.java b/apex/appsearch/framework/java/external/android/app/appsearch/SearchSpec.java
index 68e31f0..400b630 100644
--- a/apex/appsearch/framework/java/external/android/app/appsearch/SearchSpec.java
+++ b/apex/appsearch/framework/java/external/android/app/appsearch/SearchSpec.java
@@ -23,6 +23,7 @@
import android.app.appsearch.exceptions.AppSearchException;
import android.app.appsearch.exceptions.IllegalSearchSpecException;
import android.os.Bundle;
+import android.util.ArrayMap;
import com.android.internal.util.Preconditions;
@@ -33,6 +34,8 @@
import java.util.Collection;
import java.util.Collections;
import java.util.List;
+import java.util.Map;
+import java.util.Set;
/**
* This class represents the specification logic for AppSearch. It can be used to set the type of
@@ -40,6 +43,15 @@
*/
// TODO(sidchhabra) : AddResultSpec fields for Snippets etc.
public final class SearchSpec {
+ /**
+ * Schema type to be used in {@link SearchSpec.Builder#addProjectionTypePropertyPath} to apply
+ * property paths to all results, excepting any types that have had their own, specific property
+ * paths set.
+ *
+ * @hide
+ */
+ public static final String PROJECTION_SCHEMA_TYPE_WILDCARD = "*";
+
static final String TERM_MATCH_TYPE_FIELD = "termMatchType";
static final String SCHEMA_TYPE_FIELD = "schemaType";
static final String NAMESPACE_FIELD = "namespace";
@@ -49,6 +61,7 @@
static final String SNIPPET_COUNT_FIELD = "snippetCount";
static final String SNIPPET_COUNT_PER_PROPERTY_FIELD = "snippetCountPerProperty";
static final String MAX_SNIPPET_FIELD = "maxSnippet";
+ static final String PROJECTION_TYPE_PROPERTY_PATHS_FIELD = "projectionTypeFieldMasks";
/** @hide */
public static final int DEFAULT_NUM_PER_PAGE = 10;
@@ -206,12 +219,35 @@
return mBundle.getInt(MAX_SNIPPET_FIELD);
}
+ /**
+ * Returns a map from schema type to property paths to be used for projection.
+ *
+ * <p>If the map is empty, then all properties will be retrieved for all results.
+ *
+ * <p>Calling this function repeatedly is inefficient. Prefer to retain the Map returned by this
+ * function, rather than calling it multiple times.
+ *
+ * @hide
+ */
+ @NonNull
+ public Map<String, List<String>> getProjectionTypePropertyPaths() {
+ Bundle typePropertyPathsBundle = mBundle.getBundle(PROJECTION_TYPE_PROPERTY_PATHS_FIELD);
+ Set<String> schemaTypes = typePropertyPathsBundle.keySet();
+ Map<String, List<String>> typePropertyPathsMap = new ArrayMap<>(schemaTypes.size());
+ for (String schemaType : schemaTypes) {
+ typePropertyPathsMap.put(
+ schemaType, typePropertyPathsBundle.getStringArrayList(schemaType));
+ }
+ return typePropertyPathsMap;
+ }
+
/** Builder for {@link SearchSpec objects}. */
public static final class Builder {
private final Bundle mBundle;
private final ArrayList<String> mSchemaTypes = new ArrayList<>();
private final ArrayList<String> mNamespaces = new ArrayList<>();
+ private final Bundle mProjectionTypePropertyMasks = new Bundle();
private boolean mBuilt = false;
/** Creates a new {@link SearchSpec.Builder}. */
@@ -386,6 +422,109 @@
}
/**
+ * Adds property paths for the specified type to be used for projection. If property paths
+ * are added for a type, then only the properties referred to will be retrieved for results
+ * of that type. If a property path that is specified isn't present in a result, it will be
+ * ignored for that result. Property paths cannot be null.
+ *
+ * <p>If no property paths are added for a particular type, then all properties of results
+ * of that type will be retrieved.
+ *
+ * <p>If property path is added for the {@link SearchSpec#PROJECTION_SCHEMA_TYPE_WILDCARD},
+ * then those property paths will apply to all results, excepting any types that have their
+ * own, specific property paths set.
+ *
+ * <p>Suppose the following document is in the index.
+ *
+ * <pre>{@code
+ * Email: Document {
+ * sender: Document {
+ * name: "Mr. Person"
+ * email: "mrperson123@google.com"
+ * }
+ * recipients: [
+ * Document {
+ * name: "John Doe"
+ * email: "johndoe123@google.com"
+ * }
+ * Document {
+ * name: "Jane Doe"
+ * email: "janedoe123@google.com"
+ * }
+ * ]
+ * subject: "IMPORTANT"
+ * body: "Limited time offer!"
+ * }
+ * }</pre>
+ *
+ * <p>Then, suppose that a query for "important" is issued with the following projection
+ * type property paths:
+ *
+ * <pre>{@code
+ * {schemaType: "Email", ["subject", "sender.name", "recipients.name"]}
+ * }</pre>
+ *
+ * <p>The above document will be returned as:
+ *
+ * <pre>{@code
+ * Email: Document {
+ * sender: Document {
+ * name: "Mr. Body"
+ * }
+ * recipients: [
+ * Document {
+ * name: "John Doe"
+ * }
+ * Document {
+ * name: "Jane Doe"
+ * }
+ * ]
+ * subject: "IMPORTANT"
+ * }
+ * }</pre>
+ *
+ * @hide
+ */
+ @NonNull
+ public SearchSpec.Builder addProjectionTypePropertyPaths(
+ @NonNull String schemaType, @NonNull String... propertyPaths) {
+ Preconditions.checkNotNull(propertyPaths);
+ return addProjectionTypePropertyPaths(schemaType, Arrays.asList(propertyPaths));
+ }
+
+ /**
+ * Adds property paths for the specified type to be used for projection. If property paths
+ * are added for a type, then only the properties referred to will be retrieved for results
+ * of that type. If a property path that is specified isn't present in a result, it will be
+ * ignored for that result. Property paths cannot be null.
+ *
+ * <p>If no property paths are added for a particular type, then all properties of results
+ * of that type will be retrieved.
+ *
+ * <p>If property path is added for the {@link SearchSpec#PROJECTION_SCHEMA_TYPE_WILDCARD},
+ * then those property paths will apply to all results, excepting any types that have their
+ * own, specific property paths set.
+ *
+ * <p>{@see SearchSpec.Builder#addProjectionTypePropertyPath(String, String...)}
+ *
+ * @hide
+ */
+ @NonNull
+ public SearchSpec.Builder addProjectionTypePropertyPaths(
+ @NonNull String schemaType, @NonNull Collection<String> propertyPaths) {
+ Preconditions.checkState(!mBuilt, "Builder has already been used");
+ Preconditions.checkNotNull(schemaType);
+ Preconditions.checkNotNull(propertyPaths);
+ ArrayList<String> propertyPathsArrayList = new ArrayList<>(propertyPaths.size());
+ for (String propertyPath : propertyPaths) {
+ Preconditions.checkNotNull(propertyPath);
+ propertyPathsArrayList.add(propertyPath);
+ }
+ mProjectionTypePropertyMasks.putStringArrayList(schemaType, propertyPathsArrayList);
+ return this;
+ }
+
+ /**
* Constructs a new {@link SearchSpec} from the contents of this builder.
*
* <p>After calling this method, the builder must no longer be used.
@@ -398,6 +537,7 @@
}
mBundle.putStringArrayList(NAMESPACE_FIELD, mNamespaces);
mBundle.putStringArrayList(SCHEMA_TYPE_FIELD, mSchemaTypes);
+ mBundle.putBundle(PROJECTION_TYPE_PROPERTY_PATHS_FIELD, mProjectionTypePropertyMasks);
mBuilt = true;
return new SearchSpec(mBundle);
}
diff --git a/apex/appsearch/synced_jetpack_changeid.txt b/apex/appsearch/synced_jetpack_changeid.txt
index f9a0bed..5b818c7 100644
--- a/apex/appsearch/synced_jetpack_changeid.txt
+++ b/apex/appsearch/synced_jetpack_changeid.txt
@@ -1 +1 @@
-I0577839bfddf95a555399df441d317b00c7c7c48
+Idd770a064edfeb6dc648571fc6706c087b8e605a
diff --git a/apex/appsearch/testing/java/com/android/server/appsearch/testing/GlobalSearchSessionShimImpl.java b/apex/appsearch/testing/java/com/android/server/appsearch/testing/GlobalSearchSessionShimImpl.java
index 67af6b1..9e22bf6 100644
--- a/apex/appsearch/testing/java/com/android/server/appsearch/testing/GlobalSearchSessionShimImpl.java
+++ b/apex/appsearch/testing/java/com/android/server/appsearch/testing/GlobalSearchSessionShimImpl.java
@@ -20,6 +20,7 @@
import android.app.appsearch.AppSearchManager;
import android.app.appsearch.AppSearchResult;
import android.app.appsearch.GlobalSearchSession;
+import android.app.appsearch.GlobalSearchSessionShim;
import android.app.appsearch.SearchResults;
import android.app.appsearch.SearchResultsShim;
import android.app.appsearch.SearchSpec;
@@ -40,7 +41,7 @@
* a consistent interface.
* @hide
*/
-public class GlobalSearchSessionShimImpl {
+public class GlobalSearchSessionShimImpl implements GlobalSearchSessionShim {
private final GlobalSearchSession mGlobalSearchSession;
private final ExecutorService mExecutor;
@@ -64,6 +65,7 @@
}
@NonNull
+ @Override
public SearchResultsShim query(
@NonNull String queryExpression, @NonNull SearchSpec searchSpec) {
SearchResults searchResults =
diff --git a/apex/appsearch/testing/java/com/android/server/appsearch/testing/external/AppSearchTestUtils.java b/apex/appsearch/testing/java/com/android/server/appsearch/testing/external/AppSearchTestUtils.java
index 9653def..459fd151 100644
--- a/apex/appsearch/testing/java/com/android/server/appsearch/testing/external/AppSearchTestUtils.java
+++ b/apex/appsearch/testing/java/com/android/server/appsearch/testing/external/AppSearchTestUtils.java
@@ -17,6 +17,7 @@
package com.android.server.appsearch.testing;
import static com.google.common.truth.Truth.assertThat;
+import static com.google.common.truth.Truth.assertWithMessage;
import android.app.appsearch.AppSearchBatchResult;
import android.app.appsearch.AppSearchSessionShim;
@@ -25,8 +26,6 @@
import android.app.appsearch.SearchResult;
import android.app.appsearch.SearchResultsShim;
-import junit.framework.AssertionFailedError;
-
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.Future;
@@ -36,9 +35,9 @@
public static <K, V> AppSearchBatchResult<K, V> checkIsBatchResultSuccess(
Future<AppSearchBatchResult<K, V>> future) throws Exception {
AppSearchBatchResult<K, V> result = future.get();
- if (!result.isSuccess()) {
- throw new AssertionFailedError("AppSearchBatchResult not successful: " + result);
- }
+ assertWithMessage("AppSearchBatchResult not successful: " + result)
+ .that(result.isSuccess())
+ .isTrue();
return result;
}
diff --git a/apex/jobscheduler/service/java/com/android/server/job/JobSchedulerService.java b/apex/jobscheduler/service/java/com/android/server/job/JobSchedulerService.java
index 1910553..df0a0ee 100644
--- a/apex/jobscheduler/service/java/com/android/server/job/JobSchedulerService.java
+++ b/apex/jobscheduler/service/java/com/android/server/job/JobSchedulerService.java
@@ -1502,11 +1502,14 @@
mControllers.add(mBatteryController);
mStorageController = new StorageController(this);
mControllers.add(mStorageController);
- mControllers.add(new BackgroundJobsController(this));
+ final BackgroundJobsController backgroundJobsController =
+ new BackgroundJobsController(this);
+ mControllers.add(backgroundJobsController);
mControllers.add(new ContentObserverController(this));
mDeviceIdleJobsController = new DeviceIdleJobsController(this);
mControllers.add(mDeviceIdleJobsController);
- mQuotaController = new QuotaController(this);
+ mQuotaController =
+ new QuotaController(this, backgroundJobsController, connectivityController);
mControllers.add(mQuotaController);
mControllers.add(new ComponentController(this));
diff --git a/apex/jobscheduler/service/java/com/android/server/job/controllers/BackgroundJobsController.java b/apex/jobscheduler/service/java/com/android/server/job/controllers/BackgroundJobsController.java
index f647db9..04d6947 100644
--- a/apex/jobscheduler/service/java/com/android/server/job/controllers/BackgroundJobsController.java
+++ b/apex/jobscheduler/service/java/com/android/server/job/controllers/BackgroundJobsController.java
@@ -78,6 +78,11 @@
}
@Override
+ public void evaluateStateLocked(JobStatus jobStatus) {
+ updateSingleJobRestrictionLocked(jobStatus, UNKNOWN);
+ }
+
+ @Override
public void dumpControllerStateLocked(final IndentingPrintWriter pw,
final Predicate<JobStatus> predicate) {
mAppStateTracker.dump(pw);
diff --git a/apex/jobscheduler/service/java/com/android/server/job/controllers/JobStatus.java b/apex/jobscheduler/service/java/com/android/server/job/controllers/JobStatus.java
index cd71247..51525e0 100644
--- a/apex/jobscheduler/service/java/com/android/server/job/controllers/JobStatus.java
+++ b/apex/jobscheduler/service/java/com/android/server/job/controllers/JobStatus.java
@@ -1151,6 +1151,11 @@
if (setConstraintSatisfied(CONSTRAINT_WITHIN_EXPEDITED_QUOTA, state)) {
// The constraint was changed. Update the ready flag.
mReadyWithinExpeditedQuota = state;
+ // DeviceIdleJobsController currently only tracks jobs with the WILL_BE_FOREGROUND flag.
+ // Making it also track requested-expedited jobs would add unnecessary hops since the
+ // controller would then defer to canRunInDoze. Avoid the hops and just update
+ // mReadyNotDozing directly.
+ mReadyNotDozing = isConstraintSatisfied(CONSTRAINT_DEVICE_NOT_DOZING) || canRunInDoze();
return true;
}
return false;
diff --git a/apex/jobscheduler/service/java/com/android/server/job/controllers/QuotaController.java b/apex/jobscheduler/service/java/com/android/server/job/controllers/QuotaController.java
index 7b87dfb..2d55aa5 100644
--- a/apex/jobscheduler/service/java/com/android/server/job/controllers/QuotaController.java
+++ b/apex/jobscheduler/service/java/com/android/server/job/controllers/QuotaController.java
@@ -347,6 +347,9 @@
private final QcHandler mHandler;
private final QcConstants mQcConstants;
+ private final BackgroundJobsController mBackgroundJobsController;
+ private final ConnectivityController mConnectivityController;
+
/** How much time each app will have to run jobs within their standby bucket window. */
private long mAllowedTimePerPeriodMs = QcConstants.DEFAULT_ALLOWED_TIME_PER_PERIOD_MS;
@@ -552,7 +555,9 @@
*/
private static final int MSG_PROCESS_USAGE_EVENT = 5;
- public QuotaController(JobSchedulerService service) {
+ public QuotaController(@NonNull JobSchedulerService service,
+ @NonNull BackgroundJobsController backgroundJobsController,
+ @NonNull ConnectivityController connectivityController) {
super(service);
mHandler = new QcHandler(mContext.getMainLooper());
mChargeTracker = new ChargingTracker();
@@ -560,6 +565,8 @@
mActivityManagerInternal = LocalServices.getService(ActivityManagerInternal.class);
mAlarmManager = (AlarmManager) mContext.getSystemService(Context.ALARM_SERVICE);
mQcConstants = new QcConstants();
+ mBackgroundJobsController = backgroundJobsController;
+ mConnectivityController = connectivityController;
final IntentFilter filter = new IntentFilter(Intent.ACTION_PACKAGE_ADDED);
mContext.registerReceiverAsUser(mPackageAddedReceiver, UserHandle.ALL, filter, null, null);
@@ -596,7 +603,7 @@
final boolean outOfEJQuota;
if (jobStatus.isRequestedExpeditedJob()) {
final boolean isWithinEJQuota = isWithinEJQuotaLocked(jobStatus);
- jobStatus.setExpeditedJobQuotaConstraintSatisfied(isWithinEJQuota);
+ setExpeditedConstraintSatisfied(jobStatus, isWithinEJQuota);
outOfEJQuota = !isWithinEJQuota;
} else {
outOfEJQuota = false;
@@ -1473,7 +1480,7 @@
if (js.isRequestedExpeditedJob()) {
boolean isWithinEJQuota = isWithinEJQuotaLocked(js);
- changed |= js.setExpeditedJobQuotaConstraintSatisfied(isWithinEJQuota);
+ changed |= setExpeditedConstraintSatisfied(js, isWithinEJQuota);
outOfEJQuota |= !isWithinEJQuota;
}
}
@@ -1499,7 +1506,7 @@
final boolean outOfEJQuota;
if (jobStatus.isRequestedExpeditedJob()) {
final boolean isWithinEJQuota = isWithinEJQuotaLocked(jobStatus);
- wasJobChanged |= jobStatus.setExpeditedJobQuotaConstraintSatisfied(isWithinEJQuota);
+ wasJobChanged |= setExpeditedConstraintSatisfied(jobStatus, isWithinEJQuota);
outOfEJQuota = !isWithinEJQuota;
} else {
outOfEJQuota = false;
@@ -1650,6 +1657,23 @@
return jobStatus.setQuotaConstraintSatisfied(isWithinQuota);
}
+ /**
+ * If the satisfaction changes, this will tell connectivity & background jobs controller to
+ * also re-evaluate their state.
+ */
+ private boolean setExpeditedConstraintSatisfied(@NonNull JobStatus jobStatus,
+ boolean isWithinQuota) {
+ if (jobStatus.setExpeditedJobQuotaConstraintSatisfied(isWithinQuota)) {
+ mBackgroundJobsController.evaluateStateLocked(jobStatus);
+ mConnectivityController.evaluateStateLocked(jobStatus);
+ if (isWithinQuota && jobStatus.isReady()) {
+ mStateChangedListener.onRunJobNow(jobStatus);
+ }
+ return true;
+ }
+ return false;
+ }
+
private final class ChargingTracker extends BroadcastReceiver {
/**
* Track whether we're charging. This has a slightly different definition than that of
diff --git a/core/api/current.txt b/core/api/current.txt
index 326bb73..f6d0d9d 100644
--- a/core/api/current.txt
+++ b/core/api/current.txt
@@ -11641,6 +11641,14 @@
method public final int compare(android.content.pm.ApplicationInfo, android.content.pm.ApplicationInfo);
}
+ public final class Attribution implements android.os.Parcelable {
+ method public int describeContents();
+ method @IdRes public int getLabel();
+ method @NonNull public String getTag();
+ method public void writeToParcel(@NonNull android.os.Parcel, int);
+ field @NonNull public static final android.os.Parcelable.Creator<android.content.pm.Attribution> CREATOR;
+ }
+
public final class ChangedPackages implements android.os.Parcelable {
ctor public ChangedPackages(int, @NonNull java.util.List<java.lang.String>);
method public int describeContents();
@@ -11890,6 +11898,7 @@
field public static final int REQUESTED_PERMISSION_GRANTED = 2; // 0x2
field public android.content.pm.ActivityInfo[] activities;
field public android.content.pm.ApplicationInfo applicationInfo;
+ field @Nullable public android.content.pm.Attribution[] attributions;
field public int baseRevisionCode;
field public android.content.pm.ConfigurationInfo[] configPreferences;
field public android.content.pm.FeatureGroupInfo[] featureGroups;
@@ -12338,6 +12347,7 @@
field public static final int FLAG_PERMISSION_WHITELIST_SYSTEM = 1; // 0x1
field public static final int FLAG_PERMISSION_WHITELIST_UPGRADE = 4; // 0x4
field public static final int GET_ACTIVITIES = 1; // 0x1
+ field public static final int GET_ATTRIBUTIONS = -2147483648; // 0x80000000
field public static final int GET_CONFIGURATIONS = 16384; // 0x4000
field @Deprecated public static final int GET_DISABLED_COMPONENTS = 512; // 0x200
field @Deprecated public static final int GET_DISABLED_UNTIL_USED_COMPONENTS = 32768; // 0x8000
@@ -16244,7 +16254,7 @@
method public static android.graphics.drawable.Icon createWithResource(android.content.Context, @DrawableRes int);
method public static android.graphics.drawable.Icon createWithResource(String, @DrawableRes int);
method public int describeContents();
- method @IdRes public int getResId();
+ method @DrawableRes public int getResId();
method @NonNull public String getResPackage();
method public int getType();
method @NonNull public android.net.Uri getUri();
@@ -18966,8 +18976,23 @@
field @NonNull public static final android.os.Parcelable.Creator<android.location.GnssAntennaInfo.SphericalCorrections> CREATOR;
}
- public final class GnssCapabilities {
- method public boolean hasGnssAntennaInfo();
+ public final class GnssCapabilities implements android.os.Parcelable {
+ method public int describeContents();
+ method public boolean hasAntennaInfo();
+ method @Deprecated public boolean hasGnssAntennaInfo();
+ method public boolean hasMeasurements();
+ method public boolean hasNavigationMessages();
+ method public void writeToParcel(@NonNull android.os.Parcel, int);
+ field @NonNull public static final android.os.Parcelable.Creator<android.location.GnssCapabilities> CREATOR;
+ }
+
+ public static final class GnssCapabilities.Builder {
+ ctor public GnssCapabilities.Builder();
+ ctor public GnssCapabilities.Builder(@NonNull android.location.GnssCapabilities);
+ method @NonNull public android.location.GnssCapabilities build();
+ method @NonNull public android.location.GnssCapabilities.Builder setHasAntennaInfo(boolean);
+ method @NonNull public android.location.GnssCapabilities.Builder setHasMeasurements(boolean);
+ method @NonNull public android.location.GnssCapabilities.Builder setHasNavigationMessages(boolean);
}
public final class GnssClock implements android.os.Parcelable {
@@ -19303,9 +19328,11 @@
method public int getGnssYearOfHardware();
method @Deprecated @Nullable @RequiresPermission(android.Manifest.permission.ACCESS_FINE_LOCATION) public android.location.GpsStatus getGpsStatus(@Nullable android.location.GpsStatus);
method @Nullable @RequiresPermission(anyOf={android.Manifest.permission.ACCESS_COARSE_LOCATION, android.Manifest.permission.ACCESS_FINE_LOCATION}) public android.location.Location getLastKnownLocation(@NonNull String);
- method @Nullable public android.location.LocationProvider getProvider(@NonNull String);
+ method @Deprecated @Nullable public android.location.LocationProvider getProvider(@NonNull String);
+ method @Nullable public android.location.ProviderProperties getProviderProperties(@NonNull String);
method @NonNull public java.util.List<java.lang.String> getProviders(boolean);
method @NonNull public java.util.List<java.lang.String> getProviders(@NonNull android.location.Criteria, boolean);
+ method public boolean hasProvider(@NonNull String);
method public boolean isLocationEnabled();
method public boolean isProviderEnabled(@NonNull String);
method @RequiresPermission(android.Manifest.permission.ACCESS_FINE_LOCATION) public boolean registerAntennaInfoListener(@NonNull java.util.concurrent.Executor, @NonNull android.location.GnssAntennaInfo.Listener);
@@ -19366,18 +19393,18 @@
field public static final String PROVIDERS_CHANGED_ACTION = "android.location.PROVIDERS_CHANGED";
}
- public class LocationProvider {
- method public int getAccuracy();
- method public String getName();
- method public int getPowerRequirement();
- method public boolean hasMonetaryCost();
- method public boolean meetsCriteria(android.location.Criteria);
- method public boolean requiresCell();
- method public boolean requiresNetwork();
- method public boolean requiresSatellite();
- method public boolean supportsAltitude();
- method public boolean supportsBearing();
- method public boolean supportsSpeed();
+ @Deprecated public class LocationProvider {
+ method @Deprecated public int getAccuracy();
+ method @Deprecated public String getName();
+ method @Deprecated public int getPowerRequirement();
+ method @Deprecated public boolean hasMonetaryCost();
+ method @Deprecated public boolean meetsCriteria(android.location.Criteria);
+ method @Deprecated public boolean requiresCell();
+ method @Deprecated public boolean requiresNetwork();
+ method @Deprecated public boolean requiresSatellite();
+ method @Deprecated public boolean supportsAltitude();
+ method @Deprecated public boolean supportsBearing();
+ method @Deprecated public boolean supportsSpeed();
field @Deprecated public static final int AVAILABLE = 2; // 0x2
field @Deprecated public static final int OUT_OF_SERVICE = 0; // 0x0
field @Deprecated public static final int TEMPORARILY_UNAVAILABLE = 1; // 0x1
@@ -19430,6 +19457,26 @@
method public void onNmeaMessage(String, long);
}
+ public final class ProviderProperties implements android.os.Parcelable {
+ method public int describeContents();
+ method public int getAccuracy();
+ method public int getPowerUsage();
+ method public boolean hasAltitudeSupport();
+ method public boolean hasBearingSupport();
+ method public boolean hasCellRequirement();
+ method public boolean hasMonetaryCost();
+ method public boolean hasNetworkRequirement();
+ method public boolean hasSatelliteRequirement();
+ method public boolean hasSpeedSupport();
+ method public void writeToParcel(@NonNull android.os.Parcel, int);
+ field public static final int ACCURACY_COARSE = 2; // 0x2
+ field public static final int ACCURACY_FINE = 1; // 0x1
+ field @NonNull public static final android.os.Parcelable.Creator<android.location.ProviderProperties> CREATOR;
+ field public static final int POWER_USAGE_HIGH = 3; // 0x3
+ field public static final int POWER_USAGE_LOW = 1; // 0x1
+ field public static final int POWER_USAGE_MEDIUM = 2; // 0x2
+ }
+
public abstract class SettingInjectorService extends android.app.Service {
ctor public SettingInjectorService(String);
method public final android.os.IBinder onBind(android.content.Intent);
@@ -21865,6 +21912,8 @@
field public static final int METADATA_KEY_VIDEO_ROTATION = 24; // 0x18
field public static final int METADATA_KEY_VIDEO_WIDTH = 18; // 0x12
field public static final int METADATA_KEY_WRITER = 11; // 0xb
+ field public static final int METADATA_KEY_XMP_LENGTH = 42; // 0x2a
+ field public static final int METADATA_KEY_XMP_OFFSET = 41; // 0x29
field public static final int METADATA_KEY_YEAR = 8; // 0x8
field public static final int OPTION_CLOSEST = 3; // 0x3
field public static final int OPTION_CLOSEST_SYNC = 2; // 0x2
@@ -45224,7 +45273,7 @@
field public static final java.util.regex.Pattern DOMAIN_NAME;
field public static final java.util.regex.Pattern EMAIL_ADDRESS;
field @Deprecated public static final String GOOD_IRI_CHAR = "a-zA-Z0-9\u00a0-\ud7ff\uf900-\ufdcf\ufdf0-\uffef";
- field public static final java.util.regex.Pattern IP_ADDRESS;
+ field @Deprecated public static final java.util.regex.Pattern IP_ADDRESS;
field public static final java.util.regex.Pattern PHONE;
field @Deprecated public static final java.util.regex.Pattern TOP_LEVEL_DOMAIN;
field @Deprecated public static final String TOP_LEVEL_DOMAIN_STR = "((aero|arpa|asia|a[cdefgilmnoqrstuwxz])|(biz|b[abdefghijmnorstvwyz])|(cat|com|coop|c[acdfghiklmnoruvxyz])|d[ejkmoz]|(edu|e[cegrstu])|f[ijkmor]|(gov|g[abdefghilmnpqrstuwy])|h[kmnrtu]|(info|int|i[delmnoqrst])|(jobs|j[emop])|k[eghimnprwyz]|l[abcikrstuvy]|(mil|mobi|museum|m[acdeghklmnopqrstuvwxyz])|(name|net|n[acefgilopruz])|(org|om)|(pro|p[aefghklmnrstwy])|qa|r[eosuw]|s[abcdeghijklmnortuvyz]|(tel|travel|t[cdfghjklmnoprtvwz])|u[agksyz]|v[aceginu]|w[fs]|(\u03b4\u03bf\u03ba\u03b9\u03bc\u03ae|\u0438\u0441\u043f\u044b\u0442\u0430\u043d\u0438\u0435|\u0440\u0444|\u0441\u0440\u0431|\u05d8\u05e2\u05e1\u05d8|\u0622\u0632\u0645\u0627\u06cc\u0634\u06cc|\u0625\u062e\u062a\u0628\u0627\u0631|\u0627\u0644\u0627\u0631\u062f\u0646|\u0627\u0644\u062c\u0632\u0627\u0626\u0631|\u0627\u0644\u0633\u0639\u0648\u062f\u064a\u0629|\u0627\u0644\u0645\u063a\u0631\u0628|\u0627\u0645\u0627\u0631\u0627\u062a|\u0628\u06be\u0627\u0631\u062a|\u062a\u0648\u0646\u0633|\u0633\u0648\u0631\u064a\u0629|\u0641\u0644\u0633\u0637\u064a\u0646|\u0642\u0637\u0631|\u0645\u0635\u0631|\u092a\u0930\u0940\u0915\u094d\u0937\u093e|\u092d\u093e\u0930\u0924|\u09ad\u09be\u09b0\u09a4|\u0a2d\u0a3e\u0a30\u0a24|\u0aad\u0abe\u0ab0\u0aa4|\u0b87\u0ba8\u0bcd\u0ba4\u0bbf\u0baf\u0bbe|\u0b87\u0bb2\u0b99\u0bcd\u0b95\u0bc8|\u0b9a\u0bbf\u0b99\u0bcd\u0b95\u0baa\u0bcd\u0baa\u0bc2\u0bb0\u0bcd|\u0baa\u0bb0\u0bbf\u0b9f\u0bcd\u0b9a\u0bc8|\u0c2d\u0c3e\u0c30\u0c24\u0c4d|\u0dbd\u0d82\u0d9a\u0dcf|\u0e44\u0e17\u0e22|\u30c6\u30b9\u30c8|\u4e2d\u56fd|\u4e2d\u570b|\u53f0\u6e7e|\u53f0\u7063|\u65b0\u52a0\u5761|\u6d4b\u8bd5|\u6e2c\u8a66|\u9999\u6e2f|\ud14c\uc2a4\ud2b8|\ud55c\uad6d|xn\\-\\-0zwm56d|xn\\-\\-11b5bs3a9aj6g|xn\\-\\-3e0b707e|xn\\-\\-45brj9c|xn\\-\\-80akhbyknj4f|xn\\-\\-90a3ac|xn\\-\\-9t4b11yi5a|xn\\-\\-clchc0ea0b2g2a9gcd|xn\\-\\-deba0ad|xn\\-\\-fiqs8s|xn\\-\\-fiqz9s|xn\\-\\-fpcrj9c3d|xn\\-\\-fzc2c9e2c|xn\\-\\-g6w251d|xn\\-\\-gecrj9c|xn\\-\\-h2brj9c|xn\\-\\-hgbk6aj7f53bba|xn\\-\\-hlcj6aya9esc7a|xn\\-\\-j6w193g|xn\\-\\-jxalpdlp|xn\\-\\-kgbechtv|xn\\-\\-kprw13d|xn\\-\\-kpry57d|xn\\-\\-lgbbat1ad8j|xn\\-\\-mgbaam7a8h|xn\\-\\-mgbayh7gpa|xn\\-\\-mgbbh1a71e|xn\\-\\-mgbc0a9azcg|xn\\-\\-mgberp4a5d4ar|xn\\-\\-o3cw4h|xn\\-\\-ogbpf8fl|xn\\-\\-p1ai|xn\\-\\-pgbs0dh|xn\\-\\-s9brj9c|xn\\-\\-wgbh1c|xn\\-\\-wgbl6a|xn\\-\\-xkc2al3hye2a|xn\\-\\-xkc2dl3a5ee0h|xn\\-\\-yfro4i67o|xn\\-\\-ygbi2ammx|xn\\-\\-zckzah|xxx)|y[et]|z[amw])";
diff --git a/core/api/module-lib-current.txt b/core/api/module-lib-current.txt
index d6b7b08..f22b0f4 100644
--- a/core/api/module-lib-current.txt
+++ b/core/api/module-lib-current.txt
@@ -80,8 +80,6 @@
public class MediaMetadataRetriever implements java.lang.AutoCloseable {
field public static final int METADATA_KEY_VIDEO_CODEC_MIME_TYPE = 40; // 0x28
- field public static final int METADATA_KEY_XMP_LENGTH = 42; // 0x2a
- field public static final int METADATA_KEY_XMP_OFFSET = 41; // 0x29
}
public class MediaServiceManager {
diff --git a/core/api/system-current.txt b/core/api/system-current.txt
index 576963d..f89f96f 100644
--- a/core/api/system-current.txt
+++ b/core/api/system-current.txt
@@ -51,6 +51,7 @@
field public static final String BIND_TELEPHONY_DATA_SERVICE = "android.permission.BIND_TELEPHONY_DATA_SERVICE";
field public static final String BIND_TELEPHONY_NETWORK_SERVICE = "android.permission.BIND_TELEPHONY_NETWORK_SERVICE";
field public static final String BIND_TEXTCLASSIFIER_SERVICE = "android.permission.BIND_TEXTCLASSIFIER_SERVICE";
+ field public static final String BIND_TIME_ZONE_PROVIDER_SERVICE = "android.permission.BIND_TIME_ZONE_PROVIDER_SERVICE";
field public static final String BIND_TRUST_AGENT = "android.permission.BIND_TRUST_AGENT";
field public static final String BIND_TV_REMOTE_SERVICE = "android.permission.BIND_TV_REMOTE_SERVICE";
field public static final String BRICK = "android.permission.BRICK";
@@ -99,7 +100,7 @@
field public static final String INJECT_EVENTS = "android.permission.INJECT_EVENTS";
field public static final String INSTALL_DYNAMIC_SYSTEM = "android.permission.INSTALL_DYNAMIC_SYSTEM";
field public static final String INSTALL_GRANT_RUNTIME_PERMISSIONS = "android.permission.INSTALL_GRANT_RUNTIME_PERMISSIONS";
- field public static final String INSTALL_LOCATION_TIME_ZONE_PROVIDER = "android.permission.INSTALL_LOCATION_TIME_ZONE_PROVIDER";
+ field public static final String INSTALL_LOCATION_TIME_ZONE_PROVIDER_SERVICE = "android.permission.INSTALL_LOCATION_TIME_ZONE_PROVIDER_SERVICE";
field public static final String INSTALL_PACKAGE_UPDATES = "android.permission.INSTALL_PACKAGE_UPDATES";
field public static final String INSTALL_SELF_UPDATES = "android.permission.INSTALL_SELF_UPDATES";
field public static final String INTENT_FILTER_VERIFICATION_AGENT = "android.permission.INTENT_FILTER_VERIFICATION_AGENT";
@@ -1346,7 +1347,6 @@
public abstract class RoleControllerService extends android.app.Service {
ctor public RoleControllerService();
- method @NonNull public android.app.role.RolePrivileges getRolePrivileges(@NonNull String);
method @WorkerThread public abstract boolean onAddRoleHolder(@NonNull String, @NonNull String, int);
method @Nullable public final android.os.IBinder onBind(@Nullable android.content.Intent);
method @WorkerThread public abstract boolean onClearRoleHolders(@NonNull String, int);
@@ -1373,18 +1373,6 @@
field public static final int MANAGE_HOLDERS_FLAG_DONT_KILL_APP = 1; // 0x1
}
- public final class RolePrivileges implements android.os.Parcelable {
- ctor public RolePrivileges(@NonNull java.util.List<java.lang.String>, @NonNull java.util.List<java.lang.String>, @NonNull java.util.List<java.lang.String>, @NonNull java.util.List<java.lang.String>);
- method public int describeContents();
- method @NonNull public java.util.List<java.lang.String> getAppOpPermissions();
- method @NonNull public java.util.List<java.lang.String> getAppOps();
- method @NonNull public java.util.List<java.lang.String> getCapabilities();
- method @NonNull public java.util.List<java.lang.String> getPermissions();
- method public void writeToParcel(@NonNull android.os.Parcel, int);
- field public static final String CAPABILITY_NOTIFICATION_LISTENER = "android.app.role.capability.NOTIFICATION_LISTENER";
- field @NonNull public static final android.os.Parcelable.Creator<android.app.role.RolePrivileges> CREATOR;
- }
-
}
package android.app.search {
@@ -3950,19 +3938,29 @@
method public void onLocationBatch(java.util.List<android.location.Location>);
}
- public final class GnssCapabilities {
+ public final class GnssCapabilities implements android.os.Parcelable {
method public boolean hasGeofencing();
method public boolean hasLowPowerMode();
method public boolean hasMeasurementCorrections();
method public boolean hasMeasurementCorrectionsExcessPathLength();
method public boolean hasMeasurementCorrectionsLosSats();
- method public boolean hasMeasurementCorrectionsReflectingPane();
- method public boolean hasMeasurements();
- method public boolean hasNavMessages();
+ method @Deprecated public boolean hasMeasurementCorrectionsReflectingPane();
+ method public boolean hasMeasurementCorrectionsReflectingPlane();
+ method @Deprecated public boolean hasNavMessages();
method @Deprecated public boolean hasSatelliteBlacklist();
method public boolean hasSatelliteBlocklist();
}
+ public static final class GnssCapabilities.Builder {
+ method @NonNull public android.location.GnssCapabilities.Builder setHasGeofencing(boolean);
+ method @NonNull public android.location.GnssCapabilities.Builder setHasLowPowerMode(boolean);
+ method @NonNull public android.location.GnssCapabilities.Builder setHasMeasurementCorrections(boolean);
+ method @NonNull public android.location.GnssCapabilities.Builder setHasMeasurementCorrectionsExcessPathLength(boolean);
+ method @NonNull public android.location.GnssCapabilities.Builder setHasMeasurementCorrectionsLosSats(boolean);
+ method @NonNull public android.location.GnssCapabilities.Builder setHasMeasurementCorrectionsReflectingPlane(boolean);
+ method @NonNull public android.location.GnssCapabilities.Builder setHasSatelliteBlocklist(boolean);
+ }
+
public final class GnssMeasurementCorrections implements android.os.Parcelable {
method public int describeContents();
method @FloatRange(from=-1000.0F, to=10000.0f) public double getAltitudeMeters();
@@ -9776,7 +9774,6 @@
method public final void reportPermanentFailure(@NonNull Throwable);
method public final void reportSuggestion(@NonNull android.service.timezone.TimeZoneProviderSuggestion);
method public final void reportUncertain();
- field public static final String BIND_PERMISSION = "android.permission.INSTALL_LOCATION_TIME_ZONE_PROVIDER";
field public static final String PRIMARY_LOCATION_TIME_ZONE_PROVIDER_SERVICE_INTERFACE = "android.service.timezone.PrimaryLocationTimeZoneProviderService";
field public static final String SECONDARY_LOCATION_TIME_ZONE_PROVIDER_SERVICE_INTERFACE = "android.service.timezone.SecondaryLocationTimeZoneProviderService";
}
@@ -12127,7 +12124,9 @@
method public void callSessionHoldFailed(android.telephony.ims.ImsReasonInfo);
method public void callSessionHoldReceived(android.telephony.ims.ImsCallProfile);
method public void callSessionInitiated(android.telephony.ims.ImsCallProfile);
- method public void callSessionInitiatedFailed(android.telephony.ims.ImsReasonInfo);
+ method @Deprecated public void callSessionInitiatedFailed(android.telephony.ims.ImsReasonInfo);
+ method public void callSessionInitiating(@NonNull android.telephony.ims.ImsCallProfile);
+ method public void callSessionInitiatingFailed(@NonNull android.telephony.ims.ImsReasonInfo);
method public void callSessionInviteParticipantsRequestDelivered();
method public void callSessionInviteParticipantsRequestFailed(android.telephony.ims.ImsReasonInfo);
method @Deprecated public void callSessionMayHandover(int, int);
diff --git a/core/api/test-current.txt b/core/api/test-current.txt
index 5b86e8d..4fb283a 100644
--- a/core/api/test-current.txt
+++ b/core/api/test-current.txt
@@ -144,15 +144,13 @@
method @RequiresPermission(android.Manifest.permission.MANAGE_ACTIVITY_TASKS) public void resizePrimarySplitScreen(@NonNull android.graphics.Rect, @NonNull android.graphics.Rect);
method @RequiresPermission(android.Manifest.permission.MANAGE_ACTIVITY_TASKS) public void resizeTask(int, android.graphics.Rect);
method @RequiresPermission(android.Manifest.permission.MANAGE_ACTIVITY_TASKS) public boolean setTaskWindowingMode(int, int, boolean) throws java.lang.SecurityException;
- method @RequiresPermission(android.Manifest.permission.MANAGE_ACTIVITY_TASKS) public boolean setTaskWindowingModeSplitScreenPrimary(int, int, boolean, boolean, android.graphics.Rect, boolean) throws java.lang.SecurityException;
+ method @RequiresPermission(android.Manifest.permission.MANAGE_ACTIVITY_TASKS) public boolean setTaskWindowingModeSplitScreenPrimary(int, boolean);
method @RequiresPermission(android.Manifest.permission.MANAGE_ACTIVITY_TASKS) public void startSystemLockTaskMode(int);
method @RequiresPermission(android.Manifest.permission.MANAGE_ACTIVITY_TASKS) public void stopSystemLockTaskMode();
method public static boolean supportsMultiWindow(android.content.Context);
method public static boolean supportsSplitScreenMultiWindow(android.content.Context);
field public static final int DEFAULT_MINIMAL_SPLIT_SCREEN_DISPLAY_SIZE_DP = 440; // 0x1b8
field public static final int INVALID_STACK_ID = -1; // 0xffffffff
- field public static final int SPLIT_SCREEN_CREATE_MODE_BOTTOM_OR_RIGHT = 1; // 0x1
- field public static final int SPLIT_SCREEN_CREATE_MODE_TOP_OR_LEFT = 0; // 0x0
}
public class ActivityView extends android.view.ViewGroup {
diff --git a/core/java/android/app/Activity.java b/core/java/android/app/Activity.java
index 294a363..55df824 100644
--- a/core/java/android/app/Activity.java
+++ b/core/java/android/app/Activity.java
@@ -890,6 +890,9 @@
@UnsupportedAppUsage
final FragmentController mFragments = FragmentController.createController(new HostCallbacks());
+ /** The options for scene transition. */
+ ActivityOptions mPendingOptions;
+
private static final class ManagedCursor {
ManagedCursor(Cursor cursor) {
mCursor = cursor;
@@ -7258,7 +7261,7 @@
}
/**
- * Retrieve the ActivityOptions passed in from the launching activity or passed back
+ * Takes the ActivityOptions passed in from the launching activity or passed back
* from an activity launched by this activity in its call to {@link
* #convertToTranslucent(TranslucentConversionListener, ActivityOptions)}
*
@@ -7267,7 +7270,10 @@
*/
@UnsupportedAppUsage
ActivityOptions getActivityOptions() {
- return ActivityOptions.fromBundle(ActivityClient.getInstance().getActivityOptions(mToken));
+ final ActivityOptions options = mPendingOptions;
+ // The option only applies once.
+ mPendingOptions = null;
+ return options;
}
/**
diff --git a/core/java/android/app/ActivityClient.java b/core/java/android/app/ActivityClient.java
index 64d795c..d465b22 100644
--- a/core/java/android/app/ActivityClient.java
+++ b/core/java/android/app/ActivityClient.java
@@ -237,14 +237,6 @@
}
}
- Bundle getActivityOptions(IBinder token) {
- try {
- return getActivityClientController().getActivityOptions(token);
- } catch (RemoteException e) {
- throw e.rethrowFromSystemServer();
- }
- }
-
public void setRequestedOrientation(IBinder token, int requestedOrientation) {
try {
getActivityClientController().setRequestedOrientation(token, requestedOrientation);
diff --git a/core/java/android/app/ActivityOptions.java b/core/java/android/app/ActivityOptions.java
index a2b9157..f541e1a 100644
--- a/core/java/android/app/ActivityOptions.java
+++ b/core/java/android/app/ActivityOptions.java
@@ -17,7 +17,6 @@
package android.app;
import static android.Manifest.permission.CONTROL_REMOTE_APP_TRANSITION_ANIMATIONS;
-import static android.app.ActivityTaskManager.SPLIT_SCREEN_CREATE_MODE_TOP_OR_LEFT;
import static android.app.WindowConfiguration.ACTIVITY_TYPE_UNDEFINED;
import static android.app.WindowConfiguration.WINDOWING_MODE_UNDEFINED;
import static android.view.Display.INVALID_DISPLAY;
@@ -256,13 +255,6 @@
"android.activity.freezeRecentTasksReordering";
/**
- * Where the split-screen-primary stack should be positioned.
- * @hide
- */
- private static final String KEY_SPLIT_SCREEN_CREATE_MODE =
- "android:activity.splitScreenCreateMode";
-
- /**
* Determines whether to disallow the outgoing activity from entering picture-in-picture as the
* result of a new activity being launched.
* @hide
@@ -373,7 +365,6 @@
private int mLaunchActivityType = ACTIVITY_TYPE_UNDEFINED;
private int mLaunchTaskId = -1;
private int mPendingIntentLaunchFlags;
- private int mSplitScreenCreateMode = SPLIT_SCREEN_CREATE_MODE_TOP_OR_LEFT;
private boolean mLockTaskMode = false;
private boolean mDisallowEnterPictureInPictureWhileLaunching;
private boolean mApplyActivityFlagsForBubbles;
@@ -1049,8 +1040,6 @@
mTaskOverlayCanResume = opts.getBoolean(KEY_TASK_OVERLAY_CAN_RESUME, false);
mAvoidMoveToFront = opts.getBoolean(KEY_AVOID_MOVE_TO_FRONT, false);
mFreezeRecentTasksReordering = opts.getBoolean(KEY_FREEZE_RECENT_TASKS_REORDERING, false);
- mSplitScreenCreateMode = opts.getInt(KEY_SPLIT_SCREEN_CREATE_MODE,
- SPLIT_SCREEN_CREATE_MODE_TOP_OR_LEFT);
mDisallowEnterPictureInPictureWhileLaunching = opts.getBoolean(
KEY_DISALLOW_ENTER_PICTURE_IN_PICTURE_WHILE_LAUNCHING, false);
mApplyActivityFlagsForBubbles = opts.getBoolean(
@@ -1469,14 +1458,9 @@
}
/** @hide */
- public int getSplitScreenCreateMode() {
- return mSplitScreenCreateMode;
- }
-
- /** @hide */
@UnsupportedAppUsage
public void setSplitScreenCreateMode(int splitScreenCreateMode) {
- mSplitScreenCreateMode = splitScreenCreateMode;
+ // Remove this method after @UnsupportedAppUsage can be removed.
}
/** @hide */
@@ -1709,9 +1693,6 @@
if (mFreezeRecentTasksReordering) {
b.putBoolean(KEY_FREEZE_RECENT_TASKS_REORDERING, mFreezeRecentTasksReordering);
}
- if (mSplitScreenCreateMode != SPLIT_SCREEN_CREATE_MODE_TOP_OR_LEFT) {
- b.putInt(KEY_SPLIT_SCREEN_CREATE_MODE, mSplitScreenCreateMode);
- }
if (mDisallowEnterPictureInPictureWhileLaunching) {
b.putBoolean(KEY_DISALLOW_ENTER_PICTURE_IN_PICTURE_WHILE_LAUNCHING,
mDisallowEnterPictureInPictureWhileLaunching);
diff --git a/core/java/android/app/ActivityTaskManager.java b/core/java/android/app/ActivityTaskManager.java
index 2060252..fbc3b0d 100644
--- a/core/java/android/app/ActivityTaskManager.java
+++ b/core/java/android/app/ActivityTaskManager.java
@@ -16,6 +16,8 @@
package android.app;
+import static android.app.WindowConfiguration.WINDOWING_MODE_SPLIT_SCREEN_PRIMARY;
+
import android.annotation.NonNull;
import android.annotation.RequiresPermission;
import android.annotation.SystemService;
@@ -58,20 +60,6 @@
public static final int INVALID_TASK_ID = -1;
/**
- * Parameter to {@link IActivityTaskManager#setTaskWindowingModeSplitScreenPrimary} which
- * specifies the position of the created docked stack at the top half of the screen if
- * in portrait mode or at the left half of the screen if in landscape mode.
- */
- public static final int SPLIT_SCREEN_CREATE_MODE_TOP_OR_LEFT = 0;
-
- /**
- * Parameter to {@link IActivityTaskManager#setTaskWindowingModeSplitScreenPrimary} which
- * specifies the position of the created docked stack at the bottom half of the screen if
- * in portrait mode or at the right half of the screen if in landscape mode.
- */
- public static final int SPLIT_SCREEN_CREATE_MODE_BOTTOM_OR_RIGHT = 1;
-
- /**
* Input parameter to {@link IActivityTaskManager#resizeTask} which indicates
* that the resize doesn't need to preserve the window, and can be skipped if bounds
* is unchanged. This mode is used by window manager in most cases.
@@ -199,28 +187,12 @@
/**
* Moves the input task to the primary-split-screen stack.
* @param taskId Id of task to move.
- * @param createMode The mode the primary split screen stack should be created in if it doesn't
- * exist already. See
- * {@link ActivityTaskManager#SPLIT_SCREEN_CREATE_MODE_TOP_OR_LEFT}
- * and
- * {@link android.app.ActivityManager
- * #SPLIT_SCREEN_CREATE_MODE_BOTTOM_OR_RIGHT}
* @param toTop If the task and stack should be moved to the top.
- * @param animate Whether we should play an animation for the moving the task
- * @param initialBounds If the primary stack gets created, it will use these bounds for the
- * docked stack. Pass {@code null} to use default bounds.
- * @param showRecents If the recents activity should be shown on the other side of the task
- * going into split-screen mode.
* @return Whether the task was successfully put into splitscreen.
*/
@RequiresPermission(android.Manifest.permission.MANAGE_ACTIVITY_TASKS)
- public boolean setTaskWindowingModeSplitScreenPrimary(int taskId, int createMode, boolean toTop,
- boolean animate, Rect initialBounds, boolean showRecents) throws SecurityException {
- try {
- return getService().setTaskWindowingModeSplitScreenPrimary(taskId, toTop);
- } catch (RemoteException e) {
- throw e.rethrowFromSystemServer();
- }
+ public boolean setTaskWindowingModeSplitScreenPrimary(int taskId, boolean toTop) {
+ return setTaskWindowingMode(taskId, WINDOWING_MODE_SPLIT_SCREEN_PRIMARY, toTop);
}
/**
diff --git a/core/java/android/app/ActivityThread.java b/core/java/android/app/ActivityThread.java
index 69482bc..2fe1711 100644
--- a/core/java/android/app/ActivityThread.java
+++ b/core/java/android/app/ActivityThread.java
@@ -567,6 +567,9 @@
@UnsupportedAppUsage
boolean mPreserveWindow;
+ /** The options for scene transition. */
+ ActivityOptions mActivityOptions;
+
/**
* If non-null, the activity is launching with a specified rotation, the adjustments should
* be consumed before activity creation.
@@ -587,8 +590,8 @@
ActivityInfo info, Configuration overrideConfig, CompatibilityInfo compatInfo,
String referrer, IVoiceInteractor voiceInteractor, Bundle state,
PersistableBundle persistentState, List<ResultInfo> pendingResults,
- List<ReferrerIntent> pendingNewIntents, boolean isForward,
- ProfilerInfo profilerInfo, ClientTransactionHandler client,
+ List<ReferrerIntent> pendingNewIntents, ActivityOptions activityOptions,
+ boolean isForward, ProfilerInfo profilerInfo, ClientTransactionHandler client,
IBinder assistToken, FixedRotationAdjustments fixedRotationAdjustments) {
this.token = token;
this.assistToken = assistToken;
@@ -607,6 +610,7 @@
this.overrideConfig = overrideConfig;
this.packageInfo = client.getPackageInfoNoCheck(activityInfo.applicationInfo,
compatInfo);
+ mActivityOptions = activityOptions;
mPendingFixedRotationAdjustments = fixedRotationAdjustments;
init();
}
@@ -3469,6 +3473,10 @@
activity.setTheme(theme);
}
+ if (r.mActivityOptions != null) {
+ activity.mPendingOptions = r.mActivityOptions;
+ r.mActivityOptions = null;
+ }
activity.mCalled = false;
if (r.isPersistable()) {
mInstrumentation.callActivityOnCreate(activity, r.state, r.persistentState);
@@ -3509,7 +3517,7 @@
@Override
public void handleStartActivity(ActivityClientRecord r,
- PendingTransactionActions pendingActions) {
+ PendingTransactionActions pendingActions, ActivityOptions activityOptions) {
final Activity activity = r.activity;
if (!r.stopped) {
throw new IllegalStateException("Can't start activity that is not stopped.");
@@ -3520,6 +3528,9 @@
}
unscheduleGcIdler();
+ if (activityOptions != null) {
+ activity.mPendingOptions = activityOptions;
+ }
// Start
activity.performStart("handleStartActivity");
diff --git a/core/java/android/app/ClientTransactionHandler.java b/core/java/android/app/ClientTransactionHandler.java
index ac50676..0e1c827 100644
--- a/core/java/android/app/ClientTransactionHandler.java
+++ b/core/java/android/app/ClientTransactionHandler.java
@@ -164,7 +164,7 @@
/** Perform activity start. */
public abstract void handleStartActivity(@NonNull ActivityClientRecord r,
- PendingTransactionActions pendingActions);
+ PendingTransactionActions pendingActions, ActivityOptions activityOptions);
/** Get package info. */
public abstract LoadedApk getPackageInfoNoCheck(ApplicationInfo ai,
diff --git a/core/java/android/app/IActivityClientController.aidl b/core/java/android/app/IActivityClientController.aidl
index e1e0a8a..ebf1027 100644
--- a/core/java/android/app/IActivityClientController.aidl
+++ b/core/java/android/app/IActivityClientController.aidl
@@ -32,15 +32,15 @@
*/
interface IActivityClientController {
oneway void activityIdle(in IBinder token, in Configuration config, in boolean stopProfiling);
- void activityResumed(in IBinder token);
- void activityTopResumedStateLost();
- void activityPaused(in IBinder token);
- void activityStopped(in IBinder token, in Bundle state, in PersistableBundle persistentState,
- in CharSequence description);
+ oneway void activityResumed(in IBinder token);
+ oneway void activityTopResumedStateLost();
+ oneway void activityPaused(in IBinder token);
+ oneway void activityStopped(in IBinder token, in Bundle state,
+ in PersistableBundle persistentState, in CharSequence description);
oneway void activityDestroyed(in IBinder token);
- void activityRelaunched(in IBinder token);
+ oneway void activityRelaunched(in IBinder token);
- void reportSizeConfigurations(in IBinder token, in int[] horizontalSizeConfiguration,
+ oneway void reportSizeConfigurations(in IBinder token, in int[] horizontalSizeConfiguration,
in int[] verticalSizeConfigurations, in int[] smallestWidthConfigurations);
boolean moveActivityTaskToBack(in IBinder token, boolean nonRoot);
boolean shouldUpRecreateTask(in IBinder token, in String destAffinity);
@@ -60,7 +60,6 @@
String getCallingPackage(in IBinder token);
int getLaunchedFromUid(in IBinder token);
String getLaunchedFromPackage(in IBinder token);
- Bundle getActivityOptions(in IBinder token);
void setRequestedOrientation(in IBinder token, int requestedOrientation);
int getRequestedOrientation(in IBinder token);
@@ -75,8 +74,8 @@
void setPictureInPictureParams(in IBinder token, in PictureInPictureParams params);
void toggleFreeformWindowingMode(in IBinder token);
- void startLockTaskModeByToken(in IBinder token);
- void stopLockTaskModeByToken(in IBinder token);
+ oneway void startLockTaskModeByToken(in IBinder token);
+ oneway void stopLockTaskModeByToken(in IBinder token);
oneway void showLockTaskEscapeMessage(in IBinder token);
void setTaskDescription(in IBinder token, in ActivityManager.TaskDescription values);
@@ -85,16 +84,16 @@
void startLocalVoiceInteraction(in IBinder token, in Bundle options);
void stopLocalVoiceInteraction(in IBinder token);
- void setShowWhenLocked(in IBinder token, boolean showWhenLocked);
- void setInheritShowWhenLocked(in IBinder token, boolean setInheritShownWhenLocked);
- void setTurnScreenOn(in IBinder token, boolean turnScreenOn);
- void reportActivityFullyDrawn(in IBinder token, boolean restoredFromBundle);
- void overridePendingTransition(in IBinder token, in String packageName,
+ oneway void setShowWhenLocked(in IBinder token, boolean showWhenLocked);
+ oneway void setInheritShowWhenLocked(in IBinder token, boolean setInheritShownWhenLocked);
+ oneway void setTurnScreenOn(in IBinder token, boolean turnScreenOn);
+ oneway void reportActivityFullyDrawn(in IBinder token, boolean restoredFromBundle);
+ oneway void overridePendingTransition(in IBinder token, in String packageName,
int enterAnim, int exitAnim);
int setVrMode(in IBinder token, boolean enabled, in ComponentName packageName);
/** See {@link android.app.Activity#setDisablePreviewScreenshots}. */
- void setDisablePreviewScreenshots(in IBinder token, boolean disable);
+ oneway void setDisablePreviewScreenshots(in IBinder token, boolean disable);
/** Registers remote animations for a specific activity. */
void registerRemoteAnimations(in IBinder token, in RemoteAnimationDefinition definition);
@@ -106,5 +105,5 @@
* Reports that an Activity received a back key press when there were no additional activities
* on the back stack.
*/
- void onBackPressedOnTaskRoot(in IBinder token);
+ oneway void onBackPressedOnTaskRoot(in IBinder token);
}
diff --git a/core/java/android/app/IActivityTaskManager.aidl b/core/java/android/app/IActivityTaskManager.aidl
index 523c155..1d65711 100644
--- a/core/java/android/app/IActivityTaskManager.aidl
+++ b/core/java/android/app/IActivityTaskManager.aidl
@@ -218,7 +218,7 @@
*/
boolean setTaskWindowingMode(int taskId, int windowingMode, boolean toTop);
void moveTaskToRootTask(int taskId, int rootTaskId, boolean toTop);
- boolean setTaskWindowingModeSplitScreenPrimary(int taskId, boolean toTop);
+
/**
* Removes root tasks in the input windowing modes from the system if they are of activity type
* ACTIVITY_TYPE_STANDARD or ACTIVITY_TYPE_UNDEFINED
diff --git a/core/java/android/app/INotificationManager.aidl b/core/java/android/app/INotificationManager.aidl
index a8ce73d..697a377 100644
--- a/core/java/android/app/INotificationManager.aidl
+++ b/core/java/android/app/INotificationManager.aidl
@@ -35,6 +35,7 @@
import android.service.notification.IConditionListener;
import android.service.notification.IConditionProvider;
import android.service.notification.INotificationListener;
+import android.service.notification.NotificationListenerFilter;
import android.service.notification.StatusBarNotification;
import android.app.AutomaticZenRule;
import android.service.notification.ZenModeConfig;
@@ -224,4 +225,7 @@
boolean getPrivateNotificationsAllowed();
long pullStats(long startNs, int report, boolean doAgg, out List<ParcelFileDescriptor> stats);
+
+ NotificationListenerFilter getListenerFilter(in ComponentName cn, int userId);
+ void setListenerFilter(in ComponentName cn, int userId, in NotificationListenerFilter nlf);
}
diff --git a/core/java/android/app/LocalActivityManager.java b/core/java/android/app/LocalActivityManager.java
index 2e7c9f1..74e6125 100644
--- a/core/java/android/app/LocalActivityManager.java
+++ b/core/java/android/app/LocalActivityManager.java
@@ -178,7 +178,8 @@
pendingActions = null;
}
- mActivityThread.handleStartActivity(clientRecord, pendingActions);
+ mActivityThread.handleStartActivity(clientRecord, pendingActions,
+ null /* activityOptions */);
r.curState = STARTED;
if (desiredState == RESUMED) {
diff --git a/core/java/android/app/SystemServiceRegistry.java b/core/java/android/app/SystemServiceRegistry.java
index 48d2dfe..ae1c894 100644
--- a/core/java/android/app/SystemServiceRegistry.java
+++ b/core/java/android/app/SystemServiceRegistry.java
@@ -1719,7 +1719,7 @@
synchronized (cache) {
// Return it if we already have a cached instance.
T service = (T) cache[mCacheIndex];
- if (service != null || gates[mCacheIndex] == ContextImpl.STATE_NOT_FOUND) {
+ if (service != null) {
ret = service;
break; // exit the for (;;)
}
@@ -1729,7 +1729,9 @@
// Grr... if gate is STATE_READY, then this means we initialized the service
// once but someone cleared it.
// We start over from STATE_UNINITIALIZED.
- if (gates[mCacheIndex] == ContextImpl.STATE_READY) {
+ // Similarly, if the previous attempt returned null, we'll retry again.
+ if (gates[mCacheIndex] == ContextImpl.STATE_READY
+ || gates[mCacheIndex] == ContextImpl.STATE_NOT_FOUND) {
gates[mCacheIndex] = ContextImpl.STATE_UNINITIALIZED;
}
diff --git a/core/java/android/app/role/IRoleController.aidl b/core/java/android/app/role/IRoleController.aidl
index fbf79a4..8a43d7f 100644
--- a/core/java/android/app/role/IRoleController.aidl
+++ b/core/java/android/app/role/IRoleController.aidl
@@ -16,9 +16,7 @@
package android.app.role;
-import android.app.role.RolePrivileges;
import android.os.RemoteCallback;
-import com.android.internal.infra.AndroidFuture;
/**
* @hide
@@ -42,6 +40,4 @@
in RemoteCallback callback);
void isRoleVisible(in String roleName, in RemoteCallback callback);
-
- void getRolePrivileges(in String roleName, in AndroidFuture<RolePrivileges> callback);
}
diff --git a/core/java/android/app/role/RoleControllerService.java b/core/java/android/app/role/RoleControllerService.java
index 4c6aa8d..d92c956 100644
--- a/core/java/android/app/role/RoleControllerService.java
+++ b/core/java/android/app/role/RoleControllerService.java
@@ -16,8 +16,6 @@
package android.app.role;
-import static java.util.Collections.emptyList;
-
import android.Manifest;
import android.annotation.NonNull;
import android.annotation.Nullable;
@@ -34,7 +32,6 @@
import android.os.RemoteCallback;
import android.os.UserHandle;
-import com.android.internal.infra.AndroidFuture;
import com.android.internal.util.Preconditions;
import com.android.internal.util.function.pooled.PooledLambda;
@@ -180,20 +177,6 @@
boolean visible = onIsRoleVisible(roleName);
callback.sendResult(visible ? Bundle.EMPTY : null);
}
-
- @Override
- public void getRolePrivileges(String roleName, AndroidFuture<RolePrivileges> callback) {
- enforceCallingPermission(Manifest.permission.MANAGE_ROLE_HOLDERS, null);
-
- Preconditions.checkStringNotEmpty(roleName, "roleName cannot be null or empty");
- Objects.requireNonNull(callback, "callback cannot be null");
-
- try {
- callback.complete(RoleControllerService.this.getRolePrivileges(roleName));
- } catch (Throwable t) {
- callback.completeExceptionally(t);
- }
- }
};
}
@@ -319,14 +302,4 @@
* @return whether the role should be visible to user
*/
public abstract boolean onIsRoleVisible(@NonNull String roleName);
-
- /**
- * Queries the {@link RolePrivileges privileges} that the given role grants.
- *
- * @param roleName name of the role to quey for
- * @return the {@link RolePrivileges} for the role
- */
- public @NonNull RolePrivileges getRolePrivileges(@NonNull String roleName) {
- return new RolePrivileges(emptyList(), emptyList(), emptyList(), emptyList());
- }
}
diff --git a/core/java/android/app/role/RolePrivileges.java b/core/java/android/app/role/RolePrivileges.java
deleted file mode 100644
index 5fc0b0a08..0000000
--- a/core/java/android/app/role/RolePrivileges.java
+++ /dev/null
@@ -1,221 +0,0 @@
-/*
- * Copyright (C) 2020 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-
-package android.app.role;
-
-import android.annotation.NonNull;
-import android.annotation.SystemApi;
-import android.os.Parcelable;
-
-import com.android.internal.util.DataClass;
-
-import java.util.List;
-
-/**
- * Describes a set of privileges granted by a {@link RoleManager role}
- *
- * @hide
- */
-@SystemApi
-@DataClass
-public final class RolePrivileges implements Parcelable {
-
- /**
- * An identifier of a role holder app being granted the
- * {@link android.service.notification.NotificationListenerService Notification Access}
- * privilege.
- */
- public static final String CAPABILITY_NOTIFICATION_LISTENER =
- "android.app.role.capability.NOTIFICATION_LISTENER";
-
- /**
- * Permissions granted to the role holder(s).
- */
- private @NonNull List<String> mPermissions;
- /**
- * Appop permissions granted to the role holder(s).
- */
- private @NonNull List<String> mAppOpPermissions;
- /**
- * Appops granted to the role holder(s).
- */
- private @NonNull List<String> mAppOps;
- /**
- * Special access granted to the role holder(s).
- *
- * @see #CAPABILITY_NOTIFICATION_LISTENER
- */
- private @NonNull List<String> mCapabilities;
-
-
-
- // Code below generated by codegen v1.0.22.
- //
- // DO NOT MODIFY!
- // CHECKSTYLE:OFF Generated code
- //
- // To regenerate run:
- // $ codegen $ANDROID_BUILD_TOP/frameworks/base/core/java/android/app/role/RolePrivileges.java
- //
- // To exclude the generated code from IntelliJ auto-formatting enable (one-time):
- // Settings > Editor > Code Style > Formatter Control
- //@formatter:off
-
-
- /**
- * Creates a new RolePrivileges.
- *
- * @param permissions
- * Permissions granted to the role holder(s).
- * @param appOpPermissions
- * Appop permissions granted to the role holder(s).
- * @param appOps
- * Appops granted to the role holder(s).
- * @param capabilities
- * Special access granted to the role holder(s).
- */
- @DataClass.Generated.Member
- public RolePrivileges(
- @NonNull List<String> permissions,
- @NonNull List<String> appOpPermissions,
- @NonNull List<String> appOps,
- @NonNull List<String> capabilities) {
- this.mPermissions = permissions;
- com.android.internal.util.AnnotationValidations.validate(
- NonNull.class, null, mPermissions);
- this.mAppOpPermissions = appOpPermissions;
- com.android.internal.util.AnnotationValidations.validate(
- NonNull.class, null, mAppOpPermissions);
- this.mAppOps = appOps;
- com.android.internal.util.AnnotationValidations.validate(
- NonNull.class, null, mAppOps);
- this.mCapabilities = capabilities;
- com.android.internal.util.AnnotationValidations.validate(
- NonNull.class, null, mCapabilities);
-
- // onConstructed(); // You can define this method to get a callback
- }
-
- /**
- * Permissions granted to the role holder(s).
- */
- @DataClass.Generated.Member
- public @NonNull List<String> getPermissions() {
- return mPermissions;
- }
-
- /**
- * Appop permissions granted to the role holder(s).
- */
- @DataClass.Generated.Member
- public @NonNull List<String> getAppOpPermissions() {
- return mAppOpPermissions;
- }
-
- /**
- * Appops granted to the role holder(s).
- */
- @DataClass.Generated.Member
- public @NonNull List<String> getAppOps() {
- return mAppOps;
- }
-
- /**
- * Special access granted to the role holder(s).
- *
- * @see #CAPABILITY_NOTIFICATION_LISTENER
- */
- @DataClass.Generated.Member
- public @NonNull List<String> getCapabilities() {
- return mCapabilities;
- }
-
- @Override
- @DataClass.Generated.Member
- public void writeToParcel(@NonNull android.os.Parcel dest, int flags) {
- // You can override field parcelling by defining methods like:
- // void parcelFieldName(Parcel dest, int flags) { ... }
-
- dest.writeStringList(mPermissions);
- dest.writeStringList(mAppOpPermissions);
- dest.writeStringList(mAppOps);
- dest.writeStringList(mCapabilities);
- }
-
- @Override
- @DataClass.Generated.Member
- public int describeContents() { return 0; }
-
- /** @hide */
- @SuppressWarnings({"unchecked", "RedundantCast"})
- @DataClass.Generated.Member
- /* package-private */ RolePrivileges(@NonNull android.os.Parcel in) {
- // You can override field unparcelling by defining methods like:
- // static FieldType unparcelFieldName(Parcel in) { ... }
-
- List<String> permissions = new java.util.ArrayList<>();
- in.readStringList(permissions);
- List<String> appOpPermissions = new java.util.ArrayList<>();
- in.readStringList(appOpPermissions);
- List<String> appOps = new java.util.ArrayList<>();
- in.readStringList(appOps);
- List<String> capabilities = new java.util.ArrayList<>();
- in.readStringList(capabilities);
-
- this.mPermissions = permissions;
- com.android.internal.util.AnnotationValidations.validate(
- NonNull.class, null, mPermissions);
- this.mAppOpPermissions = appOpPermissions;
- com.android.internal.util.AnnotationValidations.validate(
- NonNull.class, null, mAppOpPermissions);
- this.mAppOps = appOps;
- com.android.internal.util.AnnotationValidations.validate(
- NonNull.class, null, mAppOps);
- this.mCapabilities = capabilities;
- com.android.internal.util.AnnotationValidations.validate(
- NonNull.class, null, mCapabilities);
-
- // onConstructed(); // You can define this method to get a callback
- }
-
- @DataClass.Generated.Member
- public static final @NonNull Parcelable.Creator<RolePrivileges> CREATOR
- = new Parcelable.Creator<RolePrivileges>() {
- @Override
- public RolePrivileges[] newArray(int size) {
- return new RolePrivileges[size];
- }
-
- @Override
- public RolePrivileges createFromParcel(@NonNull android.os.Parcel in) {
- return new RolePrivileges(in);
- }
- };
-
- @DataClass.Generated(
- time = 1607546429137L,
- codegenVersion = "1.0.22",
- sourceFile = "frameworks/base/core/java/android/app/role/RolePrivileges.java",
- inputSignatures = "public static final java.lang.String CAPABILITY_NOTIFICATION_LISTENER\nprivate @android.annotation.NonNull java.util.List<java.lang.String> mPermissions\nprivate @android.annotation.NonNull java.util.List<java.lang.String> mAppOpPermissions\nprivate @android.annotation.NonNull java.util.List<java.lang.String> mAppOps\nprivate @android.annotation.NonNull java.util.List<java.lang.String> mCapabilities\nclass RolePrivileges extends java.lang.Object implements [android.os.Parcelable]\n@com.android.internal.util.DataClass")
- @Deprecated
- private void __metadata() {}
-
-
- //@formatter:on
- // End of generated code
-
-}
diff --git a/core/java/android/app/servertransaction/LaunchActivityItem.java b/core/java/android/app/servertransaction/LaunchActivityItem.java
index 3758cb4..73a9cec 100644
--- a/core/java/android/app/servertransaction/LaunchActivityItem.java
+++ b/core/java/android/app/servertransaction/LaunchActivityItem.java
@@ -21,6 +21,7 @@
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.app.ActivityClient;
+import android.app.ActivityOptions;
import android.app.ActivityThread.ActivityClientRecord;
import android.app.ClientTransactionHandler;
import android.app.IActivityClientController;
@@ -66,6 +67,7 @@
private PersistableBundle mPersistentState;
private List<ResultInfo> mPendingResults;
private List<ReferrerIntent> mPendingNewIntents;
+ private ActivityOptions mActivityOptions;
private boolean mIsForward;
private ProfilerInfo mProfilerInfo;
private IBinder mAssistToken;
@@ -92,8 +94,8 @@
Trace.traceBegin(TRACE_TAG_ACTIVITY_MANAGER, "activityStart");
ActivityClientRecord r = new ActivityClientRecord(token, mIntent, mIdent, mInfo,
mOverrideConfig, mCompatInfo, mReferrer, mVoiceInteractor, mState, mPersistentState,
- mPendingResults, mPendingNewIntents, mIsForward,
- mProfilerInfo, client, mAssistToken, mFixedRotationAdjustments);
+ mPendingResults, mPendingNewIntents, mActivityOptions, mIsForward, mProfilerInfo,
+ client, mAssistToken, mFixedRotationAdjustments);
client.handleLaunchActivity(r, pendingActions, null /* customIntent */);
Trace.traceEnd(TRACE_TAG_ACTIVITY_MANAGER);
}
@@ -114,8 +116,9 @@
Configuration curConfig, Configuration overrideConfig, CompatibilityInfo compatInfo,
String referrer, IVoiceInteractor voiceInteractor, int procState, Bundle state,
PersistableBundle persistentState, List<ResultInfo> pendingResults,
- List<ReferrerIntent> pendingNewIntents, boolean isForward, ProfilerInfo profilerInfo,
- IBinder assistToken, IActivityClientController activityClientController,
+ List<ReferrerIntent> pendingNewIntents, ActivityOptions activityOptions,
+ boolean isForward, ProfilerInfo profilerInfo, IBinder assistToken,
+ IActivityClientController activityClientController,
FixedRotationAdjustments fixedRotationAdjustments) {
LaunchActivityItem instance = ObjectPool.obtain(LaunchActivityItem.class);
if (instance == null) {
@@ -123,8 +126,8 @@
}
setValues(instance, intent, ident, info, curConfig, overrideConfig, compatInfo, referrer,
voiceInteractor, procState, state, persistentState, pendingResults,
- pendingNewIntents, isForward, profilerInfo, assistToken, activityClientController,
- fixedRotationAdjustments);
+ pendingNewIntents, activityOptions, isForward, profilerInfo, assistToken,
+ activityClientController, fixedRotationAdjustments);
return instance;
}
@@ -132,7 +135,7 @@
@Override
public void recycle() {
setValues(this, null, 0, null, null, null, null, null, null, 0, null, null, null, null,
- false, null, null, null, null);
+ null, false, null, null, null, null);
ObjectPool.recycle(this);
}
@@ -155,6 +158,7 @@
dest.writePersistableBundle(mPersistentState);
dest.writeTypedList(mPendingResults, flags);
dest.writeTypedList(mPendingNewIntents, flags);
+ dest.writeBundle(mActivityOptions != null ? mActivityOptions.toBundle() : null);
dest.writeBoolean(mIsForward);
dest.writeTypedObject(mProfilerInfo, flags);
dest.writeStrongBinder(mAssistToken);
@@ -172,7 +176,8 @@
in.readBundle(getClass().getClassLoader()),
in.readPersistableBundle(getClass().getClassLoader()),
in.createTypedArrayList(ResultInfo.CREATOR),
- in.createTypedArrayList(ReferrerIntent.CREATOR), in.readBoolean(),
+ in.createTypedArrayList(ReferrerIntent.CREATOR),
+ ActivityOptions.fromBundle(in.readBundle()), in.readBoolean(),
in.readTypedObject(ProfilerInfo.CREATOR),
in.readStrongBinder(),
IActivityClientController.Stub.asInterface(in.readStrongBinder()),
@@ -210,6 +215,7 @@
&& areBundlesEqualRoughly(mPersistentState, other.mPersistentState)
&& Objects.equals(mPendingResults, other.mPendingResults)
&& Objects.equals(mPendingNewIntents, other.mPendingNewIntents)
+ && (mActivityOptions == null) == (other.mActivityOptions == null)
&& mIsForward == other.mIsForward
&& Objects.equals(mProfilerInfo, other.mProfilerInfo)
&& Objects.equals(mAssistToken, other.mAssistToken)
@@ -230,6 +236,7 @@
result = 31 * result + getRoughBundleHashCode(mPersistentState);
result = 31 * result + Objects.hashCode(mPendingResults);
result = 31 * result + Objects.hashCode(mPendingNewIntents);
+ result = 31 * result + (mActivityOptions != null ? 1 : 0);
result = 31 * result + (mIsForward ? 1 : 0);
result = 31 * result + Objects.hashCode(mProfilerInfo);
result = 31 * result + Objects.hashCode(mAssistToken);
@@ -268,9 +275,9 @@
+ ",curConfig=" + mCurConfig + ",overrideConfig=" + mOverrideConfig
+ ",referrer=" + mReferrer + ",procState=" + mProcState + ",state=" + mState
+ ",persistentState=" + mPersistentState + ",pendingResults=" + mPendingResults
- + ",pendingNewIntents=" + mPendingNewIntents + ",profilerInfo=" + mProfilerInfo
- + ",assistToken=" + mAssistToken + ",rotationAdj=" + mFixedRotationAdjustments
- + "}";
+ + ",pendingNewIntents=" + mPendingNewIntents + ",options=" + mActivityOptions
+ + ",profilerInfo=" + mProfilerInfo + ",assistToken=" + mAssistToken
+ + ",rotationAdj=" + mFixedRotationAdjustments + "}";
}
// Using the same method to set and clear values to make sure we don't forget anything
@@ -279,8 +286,8 @@
CompatibilityInfo compatInfo, String referrer, IVoiceInteractor voiceInteractor,
int procState, Bundle state, PersistableBundle persistentState,
List<ResultInfo> pendingResults, List<ReferrerIntent> pendingNewIntents,
- boolean isForward, ProfilerInfo profilerInfo, IBinder assistToken,
- IActivityClientController activityClientController,
+ ActivityOptions activityOptions, boolean isForward, ProfilerInfo profilerInfo,
+ IBinder assistToken, IActivityClientController activityClientController,
FixedRotationAdjustments fixedRotationAdjustments) {
instance.mIntent = intent;
instance.mIdent = ident;
@@ -295,6 +302,7 @@
instance.mPersistentState = persistentState;
instance.mPendingResults = pendingResults;
instance.mPendingNewIntents = pendingNewIntents;
+ instance.mActivityOptions = activityOptions;
instance.mIsForward = isForward;
instance.mProfilerInfo = profilerInfo;
instance.mAssistToken = assistToken;
diff --git a/core/java/android/app/servertransaction/StartActivityItem.java b/core/java/android/app/servertransaction/StartActivityItem.java
index 483f9de..15f65f6 100644
--- a/core/java/android/app/servertransaction/StartActivityItem.java
+++ b/core/java/android/app/servertransaction/StartActivityItem.java
@@ -20,6 +20,7 @@
import android.annotation.NonNull;
import android.annotation.Nullable;
+import android.app.ActivityOptions;
import android.app.ActivityThread.ActivityClientRecord;
import android.app.ClientTransactionHandler;
import android.os.Parcel;
@@ -33,11 +34,13 @@
private static final String TAG = "StartActivityItem";
+ private ActivityOptions mActivityOptions;
+
@Override
public void execute(ClientTransactionHandler client, ActivityClientRecord r,
PendingTransactionActions pendingActions) {
Trace.traceBegin(TRACE_TAG_ACTIVITY_MANAGER, "startActivityItem");
- client.handleStartActivity(r, pendingActions);
+ client.handleStartActivity(r, pendingActions, mActivityOptions);
Trace.traceEnd(TRACE_TAG_ACTIVITY_MANAGER);
}
@@ -52,11 +55,12 @@
private StartActivityItem() {}
/** Obtain an instance initialized with provided params. */
- public static StartActivityItem obtain() {
+ public static StartActivityItem obtain(ActivityOptions activityOptions) {
StartActivityItem instance = ObjectPool.obtain(StartActivityItem.class);
if (instance == null) {
instance = new StartActivityItem();
}
+ instance.mActivityOptions = activityOptions;
return instance;
}
@@ -64,6 +68,7 @@
@Override
public void recycle() {
super.recycle();
+ mActivityOptions = null;
ObjectPool.recycle(this);
}
@@ -73,12 +78,12 @@
/** Write to Parcel. */
@Override
public void writeToParcel(Parcel dest, int flags) {
- // Empty
+ dest.writeBundle(mActivityOptions != null ? mActivityOptions.toBundle() : null);
}
/** Read from Parcel. */
private StartActivityItem(Parcel in) {
- // Empty
+ mActivityOptions = ActivityOptions.fromBundle(in.readBundle());
}
public static final @NonNull Creator<StartActivityItem> CREATOR =
@@ -100,17 +105,20 @@
if (o == null || getClass() != o.getClass()) {
return false;
}
- return true;
+ final StartActivityItem other = (StartActivityItem) o;
+ return (mActivityOptions == null) == (other.mActivityOptions == null);
}
@Override
public int hashCode() {
- return 17;
+ int result = 17;
+ result = 31 * result + (mActivityOptions != null ? 1 : 0);
+ return result;
}
@Override
public String toString() {
- return "StartActivityItem{}";
+ return "StartActivityItem{options=" + mActivityOptions + "}";
}
}
diff --git a/core/java/android/app/servertransaction/TransactionExecutor.java b/core/java/android/app/servertransaction/TransactionExecutor.java
index 3dcf2cb..25ff8a7 100644
--- a/core/java/android/app/servertransaction/TransactionExecutor.java
+++ b/core/java/android/app/servertransaction/TransactionExecutor.java
@@ -218,7 +218,8 @@
null /* customIntent */);
break;
case ON_START:
- mTransactionHandler.handleStartActivity(r, mPendingActions);
+ mTransactionHandler.handleStartActivity(r, mPendingActions,
+ null /* activityOptions */);
break;
case ON_RESUME:
mTransactionHandler.handleResumeActivity(r, false /* finalStateRequest */,
diff --git a/core/java/android/app/servertransaction/TransactionExecutorHelper.java b/core/java/android/app/servertransaction/TransactionExecutorHelper.java
index 56bf59b..92f7dee 100644
--- a/core/java/android/app/servertransaction/TransactionExecutorHelper.java
+++ b/core/java/android/app/servertransaction/TransactionExecutorHelper.java
@@ -186,7 +186,7 @@
switch (prevState) {
// TODO(lifecycler): Extend to support all possible states.
case ON_START:
- lifecycleItem = StartActivityItem.obtain();
+ lifecycleItem = StartActivityItem.obtain(null /* activityOptions */);
break;
case ON_PAUSE:
lifecycleItem = PauseActivityItem.obtain();
diff --git a/core/java/android/content/pm/ActivityInfo.java b/core/java/android/content/pm/ActivityInfo.java
index ddcfb92..b1ca12cd 100644
--- a/core/java/android/content/pm/ActivityInfo.java
+++ b/core/java/android/content/pm/ActivityInfo.java
@@ -18,6 +18,9 @@
import android.annotation.IntDef;
import android.annotation.TestApi;
+import android.app.compat.CompatChanges;
+import android.compat.annotation.ChangeId;
+import android.compat.annotation.Disabled;
import android.compat.annotation.UnsupportedAppUsage;
import android.content.ComponentName;
import android.content.Intent;
@@ -27,6 +30,7 @@
import android.os.Build;
import android.os.Parcel;
import android.os.Parcelable;
+import android.os.UserHandle;
import android.util.Printer;
import java.lang.annotation.Retention;
@@ -866,6 +870,47 @@
};
/**
+ * This change id forces the packages it is applied to to be resizable. We only allow resizing
+ * in fullscreen windowing mode, but not forcing the app into resizable multi-windowing mode.
+ * @hide
+ */
+ @ChangeId
+ @Disabled
+ public static final long FORCE_RESIZE_APP = 174042936L; // number refers to buganizer id
+
+ /**
+ * Return value for {@link #supportsSizeChanges()} indicating that this activity does not
+ * support size changes.
+ * @hide
+ */
+ public static final int SIZE_CHANGES_UNSUPPORTED = 0;
+
+ /**
+ * Return value for {@link #supportsSizeChanges()} indicating that this activity supports size
+ * changes due to the android.supports_size_changes metadata flag being set either on
+ * application or on activity level.
+ * @hide
+ */
+ public static final int SIZE_CHANGES_SUPPORTED_METADATA = 1;
+
+ /**
+ * Return value for {@link #supportsSizeChanges()} indicating that this activity has been
+ * overridden to support size changes through the compat framework change id
+ * {@link #FORCE_RESIZE_APP}.
+ * @hide
+ */
+ public static final int SIZE_CHANGES_SUPPORTED_OVERRIDE = 2;
+
+ /** @hide */
+ @IntDef(prefix = { "SIZE_CHANGES_" }, value = {
+ SIZE_CHANGES_UNSUPPORTED,
+ SIZE_CHANGES_SUPPORTED_METADATA,
+ SIZE_CHANGES_SUPPORTED_OVERRIDE,
+ })
+ @Retention(RetentionPolicy.SOURCE)
+ public @interface SizeChangesSupportMode {}
+
+ /**
* Convert Java change bits to native.
*
* @hide
@@ -1146,6 +1191,25 @@
return (flags & FLAG_SUPPORTS_PICTURE_IN_PICTURE) != 0;
}
+ /**
+ * Returns whether the activity supports size changes.
+ * @hide
+ */
+ @SizeChangesSupportMode
+ public int supportsSizeChanges() {
+ if (supportsSizeChanges) {
+ return SIZE_CHANGES_SUPPORTED_METADATA;
+ }
+
+ if (CompatChanges.isChangeEnabled(FORCE_RESIZE_APP,
+ applicationInfo.packageName,
+ UserHandle.getUserHandleForUid(applicationInfo.uid))) {
+ return SIZE_CHANGES_SUPPORTED_OVERRIDE;
+ }
+
+ return SIZE_CHANGES_UNSUPPORTED;
+ }
+
/** @hide */
@UnsupportedAppUsage
public static boolean isResizeableMode(int mode) {
@@ -1186,6 +1250,20 @@
}
}
+ /** @hide */
+ public static String sizeChangesSupportModeToString(@SizeChangesSupportMode int mode) {
+ switch (mode) {
+ case SIZE_CHANGES_UNSUPPORTED:
+ return "SIZE_CHANGES_UNSUPPORTED";
+ case SIZE_CHANGES_SUPPORTED_METADATA:
+ return "SIZE_CHANGES_SUPPORTED_METADATA";
+ case SIZE_CHANGES_SUPPORTED_OVERRIDE:
+ return "SIZE_CHANGES_SUPPORTED_OVERRIDE";
+ default:
+ return "unknown=" + mode;
+ }
+ }
+
public void dump(Printer pw, String prefix) {
dump(pw, prefix, DUMP_FLAG_ALL);
}
diff --git a/core/java/android/app/role/RolePrivileges.aidl b/core/java/android/content/pm/Attribution.aidl
similarity index 91%
rename from core/java/android/app/role/RolePrivileges.aidl
rename to core/java/android/content/pm/Attribution.aidl
index 1561ad4..909fdb5 100644
--- a/core/java/android/app/role/RolePrivileges.aidl
+++ b/core/java/android/content/pm/Attribution.aidl
@@ -14,7 +14,6 @@
* limitations under the License.
*/
+package android.content.pm;
-package android.app.role;
-
-parcelable RolePrivileges;
+parcelable Attribution;
diff --git a/core/java/android/content/pm/Attribution.java b/core/java/android/content/pm/Attribution.java
new file mode 100644
index 0000000..989a5b9
--- /dev/null
+++ b/core/java/android/content/pm/Attribution.java
@@ -0,0 +1,160 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.content.pm;
+
+import android.annotation.IdRes;
+import android.annotation.NonNull;
+import android.os.Parcel;
+import android.os.Parcelable;
+
+import com.android.internal.util.DataClass;
+
+/**
+ * Information about an attribution declared by a package. This corresponds to the information
+ * collected from the AndroidManifest.xml's <attribution> tags.
+ */
+@DataClass(genHiddenConstructor = true)
+public final class Attribution implements Parcelable {
+
+ /**
+ * The tag of this attribution. From the <manifest> tag's "tag" attribute
+ */
+ private @NonNull String mTag;
+
+ /**
+ * The resource ID of the label of the attribution From the <manifest> tag's "label"
+ * attribute
+ */
+ private final @IdRes int mLabel;
+
+
+
+ // Code below generated by codegen v1.0.22.
+ //
+ // DO NOT MODIFY!
+ // CHECKSTYLE:OFF Generated code
+ //
+ // To regenerate run:
+ // $ codegen $ANDROID_BUILD_TOP/frameworks/base/core/java/android/content/pm/Attribution.java
+ //
+ // To exclude the generated code from IntelliJ auto-formatting enable (one-time):
+ // Settings > Editor > Code Style > Formatter Control
+ //@formatter:off
+
+
+ /**
+ * Creates a new Attribution.
+ *
+ * @param tag
+ * The tag of this attribution. From the <manifest> tag's "tag" attribute
+ * @param label
+ * The resource ID of the label of the attribution From the <manifest> tag's "label"
+ * attribute
+ * @hide
+ */
+ @DataClass.Generated.Member
+ public Attribution(
+ @NonNull String tag,
+ @IdRes int label) {
+ this.mTag = tag;
+ com.android.internal.util.AnnotationValidations.validate(
+ NonNull.class, null, mTag);
+ this.mLabel = label;
+ com.android.internal.util.AnnotationValidations.validate(
+ IdRes.class, null, mLabel);
+
+ // onConstructed(); // You can define this method to get a callback
+ }
+
+ /**
+ * The tag of this attribution. From the <manifest> tag's "tag" attribute
+ */
+ @DataClass.Generated.Member
+ public @NonNull String getTag() {
+ return mTag;
+ }
+
+ /**
+ * The resource ID of the label of the attribution From the <manifest> tag's "label"
+ * attribute
+ */
+ @DataClass.Generated.Member
+ public @IdRes int getLabel() {
+ return mLabel;
+ }
+
+ @Override
+ @DataClass.Generated.Member
+ public void writeToParcel(@NonNull Parcel dest, int flags) {
+ // You can override field parcelling by defining methods like:
+ // void parcelFieldName(Parcel dest, int flags) { ... }
+
+ dest.writeString(mTag);
+ dest.writeInt(mLabel);
+ }
+
+ @Override
+ @DataClass.Generated.Member
+ public int describeContents() { return 0; }
+
+ /** @hide */
+ @SuppressWarnings({"unchecked", "RedundantCast"})
+ @DataClass.Generated.Member
+ /* package-private */ Attribution(@NonNull Parcel in) {
+ // You can override field unparcelling by defining methods like:
+ // static FieldType unparcelFieldName(Parcel in) { ... }
+
+ String tag = in.readString();
+ int label = in.readInt();
+
+ this.mTag = tag;
+ com.android.internal.util.AnnotationValidations.validate(
+ NonNull.class, null, mTag);
+ this.mLabel = label;
+ com.android.internal.util.AnnotationValidations.validate(
+ IdRes.class, null, mLabel);
+
+ // onConstructed(); // You can define this method to get a callback
+ }
+
+ @DataClass.Generated.Member
+ public static final @NonNull Parcelable.Creator<Attribution> CREATOR
+ = new Parcelable.Creator<Attribution>() {
+ @Override
+ public Attribution[] newArray(int size) {
+ return new Attribution[size];
+ }
+
+ @Override
+ public Attribution createFromParcel(@NonNull Parcel in) {
+ return new Attribution(in);
+ }
+ };
+
+ @DataClass.Generated(
+ time = 1608139558081L,
+ codegenVersion = "1.0.22",
+ sourceFile = "frameworks/base/core/java/android/content/pm/Attribution.java",
+ inputSignatures = "private @android.annotation.NonNull java.lang.String mTag\nprivate final @android.annotation.IdRes int mLabel\nclass Attribution extends java.lang.Object implements [android.os.Parcelable]\n@com.android.internal.util.DataClass(genHiddenConstructor=true)")
+ @Deprecated
+ private void __metadata() {}
+
+
+ //@formatter:on
+ // End of generated code
+
+}
diff --git a/core/java/android/content/pm/PackageInfo.java b/core/java/android/content/pm/PackageInfo.java
index d7abb68..f991306 100644
--- a/core/java/android/content/pm/PackageInfo.java
+++ b/core/java/android/content/pm/PackageInfo.java
@@ -218,6 +218,14 @@
public int[] requestedPermissionsFlags;
/**
+ * Array of all {@link android.R.styleable#AndroidManifestAttribution
+ * <attribution>} tags included under <manifest>, or null if there were none. This
+ * is only filled if the flag {@link PackageManager#GET_ATTRIBUTIONS} was set.
+ */
+ @SuppressWarnings("ArrayReturn")
+ public @Nullable Attribution[] attributions;
+
+ /**
* Flag for {@link #requestedPermissionsFlags}: the requested permission
* is required for the application to run; the user can not optionally
* disable it. Currently all permissions are required.
@@ -471,6 +479,7 @@
dest.writeTypedArray(configPreferences, parcelableFlags);
dest.writeTypedArray(reqFeatures, parcelableFlags);
dest.writeTypedArray(featureGroups, parcelableFlags);
+ dest.writeTypedArray(attributions, parcelableFlags);
dest.writeInt(installLocation);
dest.writeInt(isStub ? 1 : 0);
dest.writeInt(coreApp ? 1 : 0);
@@ -536,6 +545,7 @@
configPreferences = source.createTypedArray(ConfigurationInfo.CREATOR);
reqFeatures = source.createTypedArray(FeatureInfo.CREATOR);
featureGroups = source.createTypedArray(FeatureGroupInfo.CREATOR);
+ attributions = source.createTypedArray(Attribution.CREATOR);
installLocation = source.readInt();
isStub = source.readInt() != 0;
coreApp = source.readInt() != 0;
diff --git a/core/java/android/content/pm/PackageManager.java b/core/java/android/content/pm/PackageManager.java
index bd27099..e074eab 100644
--- a/core/java/android/content/pm/PackageManager.java
+++ b/core/java/android/content/pm/PackageManager.java
@@ -449,6 +449,7 @@
GET_DISABLED_UNTIL_USED_COMPONENTS,
GET_UNINSTALLED_PACKAGES,
MATCH_HIDDEN_UNTIL_INSTALLED_COMPONENTS,
+ GET_ATTRIBUTIONS,
})
@Retention(RetentionPolicy.SOURCE)
public @interface PackageInfoFlags {}
@@ -842,6 +843,11 @@
*/
public static final int MATCH_DIRECT_BOOT_AUTO = 0x10000000;
+ /**
+ * {@link PackageInfo} flag: return all attributions declared in the package manifest
+ */
+ public static final int GET_ATTRIBUTIONS = 0x80000000;
+
/** @hide */
@Deprecated
public static final int MATCH_DEBUG_TRIAGED_MISSING = MATCH_DIRECT_BOOT_AUTO;
diff --git a/core/java/android/content/pm/parsing/PackageInfoWithoutStateUtils.java b/core/java/android/content/pm/parsing/PackageInfoWithoutStateUtils.java
index ddf3d90..056af77 100644
--- a/core/java/android/content/pm/parsing/PackageInfoWithoutStateUtils.java
+++ b/core/java/android/content/pm/parsing/PackageInfoWithoutStateUtils.java
@@ -22,6 +22,7 @@
import android.apex.ApexInfo;
import android.content.pm.ActivityInfo;
import android.content.pm.ApplicationInfo;
+import android.content.pm.Attribution;
import android.content.pm.ComponentInfo;
import android.content.pm.ConfigurationInfo;
import android.content.pm.FallbackCategoryProvider;
@@ -42,6 +43,7 @@
import android.content.pm.SigningInfo;
import android.content.pm.parsing.component.ComponentParseUtils;
import android.content.pm.parsing.component.ParsedActivity;
+import android.content.pm.parsing.component.ParsedAttribution;
import android.content.pm.parsing.component.ParsedComponent;
import android.content.pm.parsing.component.ParsedInstrumentation;
import android.content.pm.parsing.component.ParsedMainComponent;
@@ -276,6 +278,15 @@
}
}
}
+ if ((flags & PackageManager.GET_ATTRIBUTIONS) != 0) {
+ int size = ArrayUtils.size(pkg.getAttributions());
+ if (size > 0) {
+ pi.attributions = new Attribution[size];
+ for (int i = 0; i < size; i++) {
+ pi.attributions[i] = generateAttribution(pkg.getAttributions().get(i));
+ }
+ }
+ }
if (apexInfo != null) {
File apexFile = new File(apexInfo.modulePath);
@@ -669,6 +680,12 @@
return pgi;
}
+ @Nullable
+ public static Attribution generateAttribution(ParsedAttribution pa) {
+ if (pa == null) return null;
+ return new Attribution(pa.tag, pa.label);
+ }
+
private static void assignSharedFieldsForComponentInfo(@NonNull ComponentInfo componentInfo,
@NonNull ParsedMainComponent mainComponent) {
assignSharedFieldsForPackageItemInfo(componentInfo, mainComponent);
diff --git a/core/java/android/content/pm/parsing/component/ParsedAttribution.java b/core/java/android/content/pm/parsing/component/ParsedAttribution.java
index 02b3c7d..3a4aae1 100644
--- a/core/java/android/content/pm/parsing/component/ParsedAttribution.java
+++ b/core/java/android/content/pm/parsing/component/ParsedAttribution.java
@@ -100,7 +100,7 @@
- // Code below generated by codegen v1.0.14.
+ // Code below generated by codegen v1.0.22.
//
// DO NOT MODIFY!
// CHECKSTYLE:OFF Generated code
@@ -215,8 +215,8 @@
};
@DataClass.Generated(
- time = 1583436566499L,
- codegenVersion = "1.0.14",
+ time = 1607463855175L,
+ codegenVersion = "1.0.22",
sourceFile = "frameworks/base/core/java/android/content/pm/parsing/component/ParsedAttribution.java",
inputSignatures = "public static final int MAX_ATTRIBUTION_TAG_LEN\nprivate static final int MAX_NUM_ATTRIBUTIONS\npublic final @android.annotation.NonNull java.lang.String tag\npublic final @android.annotation.StringRes int label\npublic final @android.annotation.NonNull java.util.List<java.lang.String> inheritFrom\npublic static boolean isCombinationValid(java.util.List<android.content.pm.parsing.component.ParsedAttribution>)\nclass ParsedAttribution extends java.lang.Object implements [android.os.Parcelable]\n@com.android.internal.util.DataClass(genAidl=false)")
@Deprecated
diff --git a/core/java/android/hardware/input/InputManager.java b/core/java/android/hardware/input/InputManager.java
index 300d99b..9d20f6d 100644
--- a/core/java/android/hardware/input/InputManager.java
+++ b/core/java/android/hardware/input/InputManager.java
@@ -195,7 +195,7 @@
*/
@BlockUntrustedTouchesMode
public static final int DEFAULT_BLOCK_UNTRUSTED_TOUCHES_MODE =
- BlockUntrustedTouchesMode.PERMISSIVE;
+ BlockUntrustedTouchesMode.BLOCK;
/**
* Prevent touches from being consumed by apps if these touches passed through a non-trusted
diff --git a/core/java/android/os/BatteryStats.java b/core/java/android/os/BatteryStats.java
index a89de01..b846142 100644
--- a/core/java/android/os/BatteryStats.java
+++ b/core/java/android/os/BatteryStats.java
@@ -985,6 +985,15 @@
*/
public abstract void getDeferredJobsLineLocked(StringBuilder sb, int which);
+ /**
+ * Returns the measured energy in microjoules that the display consumed while the screen
+ * was on and uid active.
+ * Will return {@link #ENERGY_DATA_UNAVAILABLE} if data is unavailable
+ *
+ * {@hide}
+ */
+ public abstract long getScreenOnEnergy();
+
public static abstract class Sensor {
@UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P)
diff --git a/core/java/android/os/TransactionTooLargeException.java b/core/java/android/os/TransactionTooLargeException.java
index 10abf26..4d5b2a1 100644
--- a/core/java/android/os/TransactionTooLargeException.java
+++ b/core/java/android/os/TransactionTooLargeException.java
@@ -23,9 +23,11 @@
* During a remote procedure call, the arguments and the return value of the call
* are transferred as {@link Parcel} objects stored in the Binder transaction buffer.
* If the arguments or the return value are too large to fit in the transaction buffer,
- * then the call will fail and {@link TransactionTooLargeException} will be thrown.
+ * then the call will fail. {@link TransactionTooLargeException} is thrown as a
+ * heuristic when a transaction is large, and it fails, since these are the transactions
+ * which are most likely to overfill the transaction buffer.
* </p><p>
- * The Binder transaction buffer has a limited fixed size, currently 1Mb, which
+ * The Binder transaction buffer has a limited fixed size, currently 1MB, which
* is shared by all transactions in progress for the process. Consequently this
* exception can be thrown when there are many transactions in progress even when
* most of the individual transactions are of moderate size.
diff --git a/core/java/android/os/image/DynamicSystemClient.java b/core/java/android/os/image/DynamicSystemClient.java
index 58268e2..0fe8894 100644
--- a/core/java/android/os/image/DynamicSystemClient.java
+++ b/core/java/android/os/image/DynamicSystemClient.java
@@ -68,6 +68,8 @@
*/
@SystemApi
public class DynamicSystemClient {
+ private static final String TAG = "DynamicSystemClient";
+
/** @hide */
@IntDef(prefix = { "STATUS_" }, value = {
STATUS_UNKNOWN,
@@ -92,8 +94,6 @@
@Retention(RetentionPolicy.SOURCE)
public @interface StatusChangedCause {}
- private static final String TAG = "DynSystemClient";
-
/** Listener for installation status updates. */
public interface OnStatusChangedListener {
/**
@@ -240,7 +240,7 @@
private class DynSystemServiceConnection implements ServiceConnection {
public void onServiceConnected(ComponentName className, IBinder service) {
- Slog.v(TAG, "DynSystemService connected");
+ Slog.v(TAG, "onServiceConnected: " + className);
mService = new Messenger(service);
@@ -262,7 +262,7 @@
}
public void onServiceDisconnected(ComponentName className) {
- Slog.v(TAG, "DynSystemService disconnected");
+ Slog.v(TAG, "onServiceDisconnected: " + className);
mService = null;
}
}
diff --git a/core/java/android/os/image/DynamicSystemManager.java b/core/java/android/os/image/DynamicSystemManager.java
index 7f01cad..e8e4785 100644
--- a/core/java/android/os/image/DynamicSystemManager.java
+++ b/core/java/android/os/image/DynamicSystemManager.java
@@ -269,4 +269,16 @@
throw new RuntimeException(e.toString());
}
}
+
+ /**
+ * Returns the suggested scratch partition size for overlayFS.
+ */
+ @RequiresPermission(android.Manifest.permission.MANAGE_DYNAMIC_SYSTEM)
+ public long suggestScratchSize() {
+ try {
+ return mService.suggestScratchSize();
+ } catch (RemoteException e) {
+ throw new RuntimeException(e.toString());
+ }
+ }
}
diff --git a/core/java/android/os/image/IDynamicSystemService.aidl b/core/java/android/os/image/IDynamicSystemService.aidl
index df0a69b..a5a40ad 100644
--- a/core/java/android/os/image/IDynamicSystemService.aidl
+++ b/core/java/android/os/image/IDynamicSystemService.aidl
@@ -125,4 +125,9 @@
* valid VBMeta block to retrieve the AVB key from.
*/
boolean getAvbPublicKey(out AvbPublicKey dst);
+
+ /**
+ * Returns the suggested scratch partition size for overlayFS.
+ */
+ long suggestScratchSize();
}
diff --git a/core/java/android/security/ConfirmationPrompt.java b/core/java/android/security/ConfirmationPrompt.java
index f67af85..2329037 100644
--- a/core/java/android/security/ConfirmationPrompt.java
+++ b/core/java/android/security/ConfirmationPrompt.java
@@ -21,6 +21,7 @@
import android.content.Context;
import android.provider.Settings;
import android.provider.Settings.SettingNotFoundException;
+import android.security.keystore.AndroidKeyStoreProvider;
import android.text.TextUtils;
import android.util.Log;
@@ -36,15 +37,15 @@
* compromised. Implementing confirmation prompts with these guarantees requires dedicated
* hardware-support and may not always be available.
*
- * <p>Confirmation prompts are typically used with an external entitity - the <i>Relying Party</i> -
+ * <p>Confirmation prompts are typically used with an external entity - the <i>Relying Party</i> -
* in the following way. The setup steps are as follows:
* <ul>
* <li> Before first use, the application generates a key-pair with the
* {@link android.security.keystore.KeyGenParameterSpec.Builder#setUserConfirmationRequired
- * CONFIRMATION tag} set. Device attestation,
- * e.g. {@link java.security.KeyStore#getCertificateChain getCertificateChain()}, is used to
- * generate a certificate chain that includes the public key (<code>Kpub</code> in the following)
- * of the newly generated key.
+ * CONFIRMATION tag} set. AndroidKeyStore key attestation, e.g.,
+ * {@link android.security.keystore.KeyGenParameterSpec.Builder#setAttestationChallenge(byte[])}
+ * is used to generate a certificate chain that includes the public key (<code>Kpub</code> in the
+ * following) of the newly generated key.
* <li> The application sends <code>Kpub</code> and the certificate chain resulting from device
* attestation to the <i>Relying Party</i>.
* <li> The <i>Relying Party</i> validates the certificate chain which involves checking the root
@@ -78,9 +79,10 @@
* previously created nonce. If all checks passes, the transaction is executed.
* </ul>
*
- * <p>A common way of implementing the "<code>promptText</code> is what is expected" check in the
- * last bullet, is to have the <i>Relying Party</i> generate <code>promptText</code> and store it
- * along the nonce in the <code>extraData</code> blob.
+ * <p>Note: It is vital to check the <code>promptText</code> because this is the only part that
+ * the user has approved. To avoid writing parsers for all of the possible locales, it is
+ * recommended that the <i>Relying Party</i> uses the same string generator as used on the device
+ * and performs a simple string comparison.
*/
public class ConfirmationPrompt {
private static final String TAG = "ConfirmationPrompt";
@@ -92,6 +94,14 @@
private Context mContext;
private final KeyStore mKeyStore = KeyStore.getInstance();
+ private AndroidProtectedConfirmation mProtectedConfirmation;
+
+ private AndroidProtectedConfirmation getService() {
+ if (mProtectedConfirmation == null) {
+ mProtectedConfirmation = new AndroidProtectedConfirmation();
+ }
+ return mProtectedConfirmation;
+ }
private void doCallback(int responseCode, byte[] dataThatWasConfirmed,
ConfirmationCallback callback) {
@@ -119,6 +129,32 @@
}
}
+ private void doCallback2(int responseCode, byte[] dataThatWasConfirmed,
+ ConfirmationCallback callback) {
+ switch (responseCode) {
+ case AndroidProtectedConfirmation.ERROR_OK:
+ callback.onConfirmed(dataThatWasConfirmed);
+ break;
+
+ case AndroidProtectedConfirmation.ERROR_CANCELED:
+ callback.onDismissed();
+ break;
+
+ case AndroidProtectedConfirmation.ERROR_ABORTED:
+ callback.onCanceled();
+ break;
+
+ case AndroidProtectedConfirmation.ERROR_SYSTEM_ERROR:
+ callback.onError(new Exception("System error returned by ConfirmationUI."));
+ break;
+
+ default:
+ callback.onError(new Exception("Unexpected responseCode=" + responseCode
+ + " from onConfirmtionPromptCompleted() callback."));
+ break;
+ }
+ }
+
private final android.os.IBinder mCallbackBinder =
new android.security.IConfirmationPromptCallback.Stub() {
@Override
@@ -144,6 +180,29 @@
}
};
+ private final android.security.apc.IConfirmationCallback mConfirmationCallback =
+ new android.security.apc.IConfirmationCallback.Stub() {
+ @Override
+ public void onCompleted(int result, byte[] dataThatWasConfirmed)
+ throws android.os.RemoteException {
+ if (mCallback != null) {
+ ConfirmationCallback callback = mCallback;
+ Executor executor = mExecutor;
+ mCallback = null;
+ mExecutor = null;
+ if (executor == null) {
+ doCallback2(result, dataThatWasConfirmed, callback);
+ } else {
+ executor.execute(new Runnable() {
+ @Override public void run() {
+ doCallback2(result, dataThatWasConfirmed, callback);
+ }
+ });
+ }
+ }
+ }
+ };
+
/**
* A builder that collects arguments, to be shown on the system-provided confirmation prompt.
*/
@@ -211,6 +270,9 @@
private static final int UI_OPTION_ACCESSIBILITY_MAGNIFIED_FLAG = 1 << 1;
private int getUiOptionsAsFlags() {
+ if (AndroidKeyStoreProvider.isKeystore2Enabled()) {
+ return getUiOptionsAsFlags2();
+ }
int uiOptionsAsFlags = 0;
ContentResolver contentResolver = mContext.getContentResolver();
int inversionEnabled = Settings.Secure.getInt(contentResolver,
@@ -226,6 +288,22 @@
return uiOptionsAsFlags;
}
+ private int getUiOptionsAsFlags2() {
+ int uiOptionsAsFlags = 0;
+ ContentResolver contentResolver = mContext.getContentResolver();
+ int inversionEnabled = Settings.Secure.getInt(contentResolver,
+ Settings.Secure.ACCESSIBILITY_DISPLAY_INVERSION_ENABLED, 0);
+ if (inversionEnabled == 1) {
+ uiOptionsAsFlags |= AndroidProtectedConfirmation.FLAG_UI_OPTION_INVERTED;
+ }
+ float fontScale = Settings.System.getFloat(contentResolver,
+ Settings.System.FONT_SCALE, (float) 1.0);
+ if (fontScale > 1.0) {
+ uiOptionsAsFlags |= AndroidProtectedConfirmation.FLAG_UI_OPTION_MAGNIFIED;
+ }
+ return uiOptionsAsFlags;
+ }
+
private static boolean isAccessibilityServiceRunning(Context context) {
boolean serviceRunning = false;
try {
@@ -270,29 +348,53 @@
mCallback = callback;
mExecutor = executor;
- int uiOptionsAsFlags = getUiOptionsAsFlags();
String locale = Locale.getDefault().toLanguageTag();
- int responseCode = mKeyStore.presentConfirmationPrompt(
- mCallbackBinder, mPromptText.toString(), mExtraData, locale, uiOptionsAsFlags);
- switch (responseCode) {
- case KeyStore.CONFIRMATIONUI_OK:
- return;
+ if (AndroidKeyStoreProvider.isKeystore2Enabled()) {
+ int uiOptionsAsFlags = getUiOptionsAsFlags2();
+ int responseCode = getService().presentConfirmationPrompt(
+ mConfirmationCallback, mPromptText.toString(), mExtraData, locale,
+ uiOptionsAsFlags);
+ switch (responseCode) {
+ case AndroidProtectedConfirmation.ERROR_OK:
+ return;
- case KeyStore.CONFIRMATIONUI_OPERATION_PENDING:
- throw new ConfirmationAlreadyPresentingException();
+ case AndroidProtectedConfirmation.ERROR_OPERATION_PENDING:
+ throw new ConfirmationAlreadyPresentingException();
- case KeyStore.CONFIRMATIONUI_UNIMPLEMENTED:
- throw new ConfirmationNotAvailableException();
+ case AndroidProtectedConfirmation.ERROR_UNIMPLEMENTED:
+ throw new ConfirmationNotAvailableException();
- case KeyStore.CONFIRMATIONUI_UIERROR:
- throw new IllegalArgumentException();
+ default:
+ // Unexpected error code.
+ Log.w(TAG,
+ "Unexpected responseCode=" + responseCode
+ + " from presentConfirmationPrompt() call.");
+ throw new IllegalArgumentException();
+ }
+ } else {
+ int uiOptionsAsFlags = getUiOptionsAsFlags();
+ int responseCode = mKeyStore.presentConfirmationPrompt(
+ mCallbackBinder, mPromptText.toString(), mExtraData, locale, uiOptionsAsFlags);
+ switch (responseCode) {
+ case KeyStore.CONFIRMATIONUI_OK:
+ return;
- default:
- // Unexpected error code.
- Log.w(TAG,
- "Unexpected responseCode=" + responseCode
- + " from presentConfirmationPrompt() call.");
- throw new IllegalArgumentException();
+ case KeyStore.CONFIRMATIONUI_OPERATION_PENDING:
+ throw new ConfirmationAlreadyPresentingException();
+
+ case KeyStore.CONFIRMATIONUI_UNIMPLEMENTED:
+ throw new ConfirmationNotAvailableException();
+
+ case KeyStore.CONFIRMATIONUI_UIERROR:
+ throw new IllegalArgumentException();
+
+ default:
+ // Unexpected error code.
+ Log.w(TAG,
+ "Unexpected responseCode=" + responseCode
+ + " from presentConfirmationPrompt() call.");
+ throw new IllegalArgumentException();
+ }
}
}
@@ -306,17 +408,33 @@
* @throws IllegalStateException if no prompt is currently being presented.
*/
public void cancelPrompt() {
- int responseCode = mKeyStore.cancelConfirmationPrompt(mCallbackBinder);
- if (responseCode == KeyStore.CONFIRMATIONUI_OK) {
- return;
- } else if (responseCode == KeyStore.CONFIRMATIONUI_OPERATION_PENDING) {
- throw new IllegalStateException();
+ if (AndroidKeyStoreProvider.isKeystore2Enabled()) {
+ int responseCode =
+ getService().cancelConfirmationPrompt(mConfirmationCallback);
+ if (responseCode == AndroidProtectedConfirmation.ERROR_OK) {
+ return;
+ } else if (responseCode == AndroidProtectedConfirmation.ERROR_OPERATION_PENDING) {
+ throw new IllegalStateException();
+ } else {
+ // Unexpected error code.
+ Log.w(TAG,
+ "Unexpected responseCode=" + responseCode
+ + " from cancelConfirmationPrompt() call.");
+ throw new IllegalStateException();
+ }
} else {
- // Unexpected error code.
- Log.w(TAG,
- "Unexpected responseCode=" + responseCode
- + " from cancelConfirmationPrompt() call.");
- throw new IllegalStateException();
+ int responseCode = mKeyStore.cancelConfirmationPrompt(mCallbackBinder);
+ if (responseCode == KeyStore.CONFIRMATIONUI_OK) {
+ return;
+ } else if (responseCode == KeyStore.CONFIRMATIONUI_OPERATION_PENDING) {
+ throw new IllegalStateException();
+ } else {
+ // Unexpected error code.
+ Log.w(TAG,
+ "Unexpected responseCode=" + responseCode
+ + " from cancelConfirmationPrompt() call.");
+ throw new IllegalStateException();
+ }
}
}
@@ -330,6 +448,9 @@
if (isAccessibilityServiceRunning(context)) {
return false;
}
+ if (AndroidKeyStoreProvider.isKeystore2Enabled()) {
+ return new AndroidProtectedConfirmation().isConfirmationPromptSupported();
+ }
return KeyStore.getInstance().isConfirmationPromptSupported();
}
}
diff --git a/location/java/com/android/internal/location/ProviderProperties.aidl b/core/java/android/service/notification/NotificationListenerFilter.aidl
similarity index 80%
copy from location/java/com/android/internal/location/ProviderProperties.aidl
copy to core/java/android/service/notification/NotificationListenerFilter.aidl
index b901444..c186b74 100644
--- a/location/java/com/android/internal/location/ProviderProperties.aidl
+++ b/core/java/android/service/notification/NotificationListenerFilter.aidl
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2012, The Android Open Source Project
+ * Copyright (c) 2020, The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -14,6 +14,7 @@
* limitations under the License.
*/
-package com.android.internal.location;
+package android.service.notification;
-parcelable ProviderProperties;
+parcelable NotificationListenerFilter;
+
diff --git a/core/java/android/service/notification/NotificationListenerFilter.java b/core/java/android/service/notification/NotificationListenerFilter.java
new file mode 100644
index 0000000..c945c2d
--- /dev/null
+++ b/core/java/android/service/notification/NotificationListenerFilter.java
@@ -0,0 +1,102 @@
+/**
+ * Copyright (c) 2020, The Android Open Source Project
+ *
+ * Licensed under the Apache License, 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.service.notification;
+
+import static android.service.notification.NotificationListenerService.FLAG_FILTER_TYPE_ALERTING;
+import static android.service.notification.NotificationListenerService.FLAG_FILTER_TYPE_CONVERSATIONS;
+import static android.service.notification.NotificationListenerService.FLAG_FILTER_TYPE_SILENT;
+
+import android.os.Parcel;
+import android.os.Parcelable;
+import android.util.ArraySet;
+
+/**
+ * Specifies a filter for what types of notifications should be bridged to notification listeners.
+ * Each requested listener will have their own filter instance.
+ * @hide
+ */
+public class NotificationListenerFilter implements Parcelable {
+ private int mAllowedNotificationTypes;
+ private ArraySet<String> mDisallowedPackages;
+
+ public NotificationListenerFilter() {
+ mAllowedNotificationTypes = FLAG_FILTER_TYPE_CONVERSATIONS
+ | FLAG_FILTER_TYPE_ALERTING
+ | FLAG_FILTER_TYPE_SILENT;
+ mDisallowedPackages = new ArraySet<>();
+ }
+
+ public NotificationListenerFilter(int types, ArraySet<String> pkgs) {
+ mAllowedNotificationTypes = types;
+ mDisallowedPackages = pkgs;
+ }
+
+ /**
+ * @hide
+ */
+ protected NotificationListenerFilter(Parcel in) {
+ mAllowedNotificationTypes = in.readInt();
+ mDisallowedPackages = (ArraySet<String>) in.readArraySet(String.class.getClassLoader());
+ }
+
+ @Override
+ public void writeToParcel(Parcel dest, int flags) {
+ dest.writeInt(mAllowedNotificationTypes);
+ dest.writeArraySet(mDisallowedPackages);
+ }
+
+ public static final Creator<NotificationListenerFilter> CREATOR =
+ new Creator<NotificationListenerFilter>() {
+ @Override
+ public NotificationListenerFilter createFromParcel(Parcel in) {
+ return new NotificationListenerFilter(in);
+ }
+
+ @Override
+ public NotificationListenerFilter[] newArray(int size) {
+ return new NotificationListenerFilter[size];
+ }
+ };
+
+ public boolean isTypeAllowed(int type) {
+ return (mAllowedNotificationTypes & type) != 0;
+ }
+
+ public boolean isPackageAllowed(String pkg) {
+ return !mDisallowedPackages.contains(pkg);
+ }
+
+ public int getTypes() {
+ return mAllowedNotificationTypes;
+ }
+
+ public ArraySet<String> getDisallowedPackages() {
+ return mDisallowedPackages;
+ }
+
+ public void setTypes(int types) {
+ mAllowedNotificationTypes = types;
+ }
+
+ public void setDisallowedPackages(ArraySet<String> pkgs) {
+ mDisallowedPackages = pkgs;
+ }
+
+ @Override
+ public int describeContents() {
+ return 0;
+ }
+}
diff --git a/core/java/android/service/notification/NotificationListenerService.java b/core/java/android/service/notification/NotificationListenerService.java
index 440eeb1..ccde0bc 100644
--- a/core/java/android/service/notification/NotificationListenerService.java
+++ b/core/java/android/service/notification/NotificationListenerService.java
@@ -242,6 +242,23 @@
public @interface NotificationCancelReason{};
/**
+ * A flag value indicating that this notification listener can see conversation type
+ * notifications.
+ * @hide
+ */
+ public static final int FLAG_FILTER_TYPE_CONVERSATIONS = 1;
+ /**
+ * A flag value indicating that this notification listener can see altering type notifications.
+ * @hide
+ */
+ public static final int FLAG_FILTER_TYPE_ALERTING = 2;
+ /**
+ * A flag value indicating that this notification listener can see silent type notifications.
+ * @hide
+ */
+ public static final int FLAG_FILTER_TYPE_SILENT = 4;
+
+ /**
* The full trim of the StatusBarNotification including all its features.
*
* @hide
diff --git a/core/java/android/service/timezone/TimeZoneProviderService.java b/core/java/android/service/timezone/TimeZoneProviderService.java
index 9533a8f..f2bf176 100644
--- a/core/java/android/service/timezone/TimeZoneProviderService.java
+++ b/core/java/android/service/timezone/TimeZoneProviderService.java
@@ -53,7 +53,7 @@
* <p>Provider discovery:
*
* <p>You must declare the service in your manifest file with the
- * {@link android.Manifest.permission#INSTALL_LOCATION_TIME_ZONE_PROVIDER} permission,
+ * {@link android.Manifest.permission#BIND_TIME_ZONE_PROVIDER_SERVICE} permission,
* and include an intent filter with the necessary action indicating what type of provider it is.
*
* <p>Device configuration can influence how {@link TimeZoneProviderService}s are discovered.
@@ -66,18 +66,29 @@
*
* <p>Provider types:
*
- * <p>Android currently supports up to two location-derived time zone providers. These are called
- * the "primary" and "secondary" location time zone provider, configured using {@link
- * #PRIMARY_LOCATION_TIME_ZONE_PROVIDER_SERVICE_INTERFACE} and {@link
- * #SECONDARY_LOCATION_TIME_ZONE_PROVIDER_SERVICE_INTERFACE} respectively. The primary location time
- * zone provider is started first and will be used until becomes uncertain or fails, at which point
- * the secondary provider will be started.
+ * <p>Android supports up to two <em>location-derived</em> time zone providers. These are called the
+ * "primary" and "secondary" location time zone provider. The primary location time zone provider is
+ * started first and will be used until it becomes uncertain or fails, at which point the secondary
+ * provider will be started.
*
- * For example:
+ * <p>Location-derived time zone providers are configured using {@link
+ * #PRIMARY_LOCATION_TIME_ZONE_PROVIDER_SERVICE_INTERFACE} and {@link
+ * #SECONDARY_LOCATION_TIME_ZONE_PROVIDER_SERVICE_INTERFACE} intent-filter actions respectively.
+ * Besides declaring the android:permission attribute mentioned above, the application supplying a
+ * location provider must be granted the {@link
+ * android.Manifest.permission#INSTALL_LOCATION_TIME_ZONE_PROVIDER_SERVICE} permission to be
+ * accepted by the system server.
+ *
+ * <p>For example:
* <pre>
+ * <uses-permission
+ * android:name="android.permission.INSTALL_LOCATION_TIME_ZONE_PROVIDER_SERVICE"/>
+ *
+ * ...
+ *
* <service android:name=".FooTimeZoneProviderService"
* android:exported="true"
- * android:permission="android.permission.INSTALL_LOCATION_TIME_ZONE_PROVIDER">
+ * android:permission="android.permission.BIND_TIME_ZONE_PROVIDER_SERVICE">
* <intent-filter>
* <action
* android:name="android.service.timezone.SecondaryLocationTimeZoneProviderService"
@@ -88,7 +99,6 @@
* </service>
* </pre>
*
- *
* <p>Threading:
*
* <p>Calls to {@code report} methods can be made on on any thread and will be passed asynchronously
@@ -120,14 +130,6 @@
public static final String SECONDARY_LOCATION_TIME_ZONE_PROVIDER_SERVICE_INTERFACE =
"android.service.timezone.SecondaryLocationTimeZoneProviderService";
- /**
- * The permission that a service must require to ensure that only Android system can bind to it.
- * If this permission is not enforced in the AndroidManifest of the service, the system will
- * skip that service.
- */
- public static final String BIND_PERMISSION =
- "android.permission.INSTALL_LOCATION_TIME_ZONE_PROVIDER";
-
private final TimeZoneProviderServiceWrapper mWrapper = new TimeZoneProviderServiceWrapper();
/** Set by {@link #mHandler} thread. */
diff --git a/core/java/android/service/wallpaper/WallpaperService.java b/core/java/android/service/wallpaper/WallpaperService.java
index 3763711..507dc7a 100644
--- a/core/java/android/service/wallpaper/WallpaperService.java
+++ b/core/java/android/service/wallpaper/WallpaperService.java
@@ -881,8 +881,7 @@
if (mSession.addToDisplay(mWindow, mLayout, View.VISIBLE,
mDisplay.getDisplayId(), mInsetsState, mWinFrames.frame,
- mWinFrames.displayCutout, inputChannel, mInsetsState,
- mTempControls) < 0) {
+ inputChannel, mInsetsState, mTempControls) < 0) {
Log.w(TAG, "Failed to add window while updating wallpaper surface.");
return;
}
@@ -924,13 +923,13 @@
int w = mWinFrames.frame.width();
int h = mWinFrames.frame.height();
- final DisplayCutout rawCutout = mWinFrames.displayCutout.get();
+ final DisplayCutout rawCutout = mInsetsState.getDisplayCutout();
final Configuration config = getResources().getConfiguration();
final Rect visibleFrame = new Rect(mWinFrames.frame);
visibleFrame.intersect(mInsetsState.getDisplayFrame());
WindowInsets windowInsets = mInsetsState.calculateInsets(visibleFrame,
null /* ignoringVisibilityState */, config.isScreenRound(),
- false /* alwaysConsumeSystemBars */, rawCutout, mLayout.softInputMode,
+ false /* alwaysConsumeSystemBars */, mLayout.softInputMode,
mLayout.flags, SYSTEM_UI_FLAG_VISIBLE, mLayout.type,
config.windowConfiguration.getWindowingMode(), null /* typeSideMap */);
diff --git a/core/java/android/util/Patterns.java b/core/java/android/util/Patterns.java
index 7ad16ff..ece069f 100644
--- a/core/java/android/util/Patterns.java
+++ b/core/java/android/util/Patterns.java
@@ -248,6 +248,13 @@
+ "[0-9]|[0-1][0-9]{2}|[1-9][0-9]|[1-9]|0)\\.(25[0-5]|2[0-4][0-9]|[0-1]"
+ "[0-9]{2}|[1-9][0-9]|[1-9]|0)\\.(25[0-5]|2[0-4][0-9]|[0-1][0-9]{2}"
+ "|[1-9][0-9]|[0-9]))";
+
+ /**
+ * Kept for backward compatibility reasons. It does not match IPv6 addresses.
+ *
+ * @deprecated Please use {@link android.net.InetAddresses#isNumericAddress(String)} instead.
+ */
+ @Deprecated
public static final Pattern IP_ADDRESS = Pattern.compile(IP_ADDRESS_STRING);
/**
diff --git a/core/java/android/view/DisplayCutout.java b/core/java/android/view/DisplayCutout.java
index 3f2dd4d..525ac53 100644
--- a/core/java/android/view/DisplayCutout.java
+++ b/core/java/android/view/DisplayCutout.java
@@ -196,6 +196,12 @@
return rects;
}
+ private void scale(float scale) {
+ for (int i = 0; i < BOUNDS_POSITION_LENGTH; ++i) {
+ mRects[i].scale(scale);
+ }
+ }
+
@Override
public int hashCode() {
int result = 0;
@@ -871,6 +877,16 @@
mInner = cutout;
}
+ public void scale(float scale) {
+ final Rect safeInsets = mInner.getSafeInsets();
+ safeInsets.scale(scale);
+ final Bounds bounds = new Bounds(mInner.mBounds.mRects, true);
+ bounds.scale(scale);
+ final Rect waterfallInsets = mInner.mWaterfallInsets.toRect();
+ waterfallInsets.scale(scale);
+ mInner = new DisplayCutout(safeInsets, Insets.of(waterfallInsets), bounds);
+ }
+
@Override
public int hashCode() {
return mInner.hashCode();
diff --git a/core/java/android/view/IWindowManager.aidl b/core/java/android/view/IWindowManager.aidl
index 025a977..68a6de8 100644
--- a/core/java/android/view/IWindowManager.aidl
+++ b/core/java/android/view/IWindowManager.aidl
@@ -728,7 +728,7 @@
* @return {@code true} if system bars are always comsumed.
*/
boolean getWindowInsets(in WindowManager.LayoutParams attrs, int displayId,
- out DisplayCutout.ParcelableWrapper outDisplayCutout, out InsetsState outInsetsState);
+ out InsetsState outInsetsState);
/**
* Called to show global actions.
diff --git a/core/java/android/view/IWindowSession.aidl b/core/java/android/view/IWindowSession.aidl
index cfdaf8c..85498cb 100644
--- a/core/java/android/view/IWindowSession.aidl
+++ b/core/java/android/view/IWindowSession.aidl
@@ -47,13 +47,11 @@
interface IWindowSession {
int addToDisplay(IWindow window, in WindowManager.LayoutParams attrs,
in int viewVisibility, in int layerStackId, in InsetsState requestedVisibility,
- out Rect outFrame, out DisplayCutout.ParcelableWrapper displayCutout,
- out InputChannel outInputChannel, out InsetsState insetsState,
+ out Rect outFrame, out InputChannel outInputChannel, out InsetsState insetsState,
out InsetsSourceControl[] activeControls);
int addToDisplayAsUser(IWindow window, in WindowManager.LayoutParams attrs,
in int viewVisibility, in int layerStackId, in int userId,
- in InsetsState requestedVisibility, out Rect outFrame,
- out DisplayCutout.ParcelableWrapper displayCutout, out InputChannel outInputChannel,
+ in InsetsState requestedVisibility, out Rect outFrame, out InputChannel outInputChannel,
out InsetsState insetsState, out InsetsSourceControl[] activeControls);
int addToDisplayWithoutInputChannel(IWindow window, in WindowManager.LayoutParams attrs,
in int viewVisibility, in int layerStackId, out InsetsState insetsState);
diff --git a/core/java/android/view/InsetsAnimationControlImpl.java b/core/java/android/view/InsetsAnimationControlImpl.java
index 75dc0c4..a89c540 100644
--- a/core/java/android/view/InsetsAnimationControlImpl.java
+++ b/core/java/android/view/InsetsAnimationControlImpl.java
@@ -334,8 +334,7 @@
private Insets getInsetsFromState(InsetsState state, Rect frame,
@Nullable @InternalInsetsSide SparseIntArray typeSideMap) {
return state.calculateInsets(frame, null /* ignoringVisibilityState */,
- false /* isScreenRound */,
- false /* alwaysConsumeSystemBars */, null /* displayCutout */,
+ false /* isScreenRound */, false /* alwaysConsumeSystemBars */,
LayoutParams.SOFT_INPUT_ADJUST_RESIZE /* legacySoftInputMode*/,
0 /* legacyWindowFlags */, 0 /* legacySystemUiFlags */, TYPE_APPLICATION,
WINDOWING_MODE_UNDEFINED, typeSideMap).getInsets(mTypes);
diff --git a/core/java/android/view/InsetsController.java b/core/java/android/view/InsetsController.java
index 49cd3a6..2d26c64 100644
--- a/core/java/android/view/InsetsController.java
+++ b/core/java/android/view/InsetsController.java
@@ -522,7 +522,6 @@
private int mLastLegacyWindowFlags;
private int mLastLegacySystemUiFlags;
private int mLastWindowingMode;
- private DisplayCutout mLastDisplayCutout;
private boolean mStartingAnimation;
private int mCaptionInsetsHeight = 0;
private boolean mAnimationsDisabled;
@@ -589,9 +588,8 @@
WindowInsets insets = state.calculateInsets(mFrame, mState /* ignoringVisibilityState*/,
mLastInsets.isRound(), mLastInsets.shouldAlwaysConsumeSystemBars(),
- mLastDisplayCutout, mLastLegacySoftInputMode, mLastLegacyWindowFlags,
- mLastLegacySystemUiFlags, mWindowType, mLastWindowingMode,
- null /* typeSideMap */);
+ mLastLegacySoftInputMode, mLastLegacyWindowFlags, mLastLegacySystemUiFlags,
+ mWindowType, mLastWindowingMode, null /* typeSideMap */);
mHost.dispatchWindowInsetsAnimationProgress(insets, mUnmodifiableTmpRunningAnims);
if (DEBUG) {
for (WindowInsetsAnimation anim : mUnmodifiableTmpRunningAnims) {
@@ -654,6 +652,7 @@
private void updateState(InsetsState newState) {
mState.setDisplayFrame(newState.getDisplayFrame());
+ mState.setDisplayCutout(newState.getDisplayCutout());
@InsetsType int disabledUserAnimationTypes = 0;
@InsetsType int[] cancelledUserAnimationTypes = {0};
for (@InternalInsetsType int type = 0; type < InsetsState.SIZE; type++) {
@@ -725,18 +724,16 @@
*/
@VisibleForTesting
public WindowInsets calculateInsets(boolean isScreenRound, boolean alwaysConsumeSystemBars,
- DisplayCutout cutout, int windowType, int windowingMode,
- int legacySoftInputMode, int legacyWindowFlags, int legacySystemUiFlags) {
+ int windowType, int windowingMode, int legacySoftInputMode, int legacyWindowFlags,
+ int legacySystemUiFlags) {
mWindowType = windowType;
mLastWindowingMode = windowingMode;
mLastLegacySoftInputMode = legacySoftInputMode;
mLastLegacyWindowFlags = legacyWindowFlags;
mLastLegacySystemUiFlags = legacySystemUiFlags;
- mLastDisplayCutout = cutout;
mLastInsets = mState.calculateInsets(mFrame, null /* ignoringVisibilityState*/,
- isScreenRound, alwaysConsumeSystemBars, cutout,
- legacySoftInputMode, legacyWindowFlags, legacySystemUiFlags,
- windowType, windowingMode, null /* typeSideMap */);
+ isScreenRound, alwaysConsumeSystemBars, legacySoftInputMode, legacyWindowFlags,
+ legacySystemUiFlags, windowType, windowingMode, null /* typeSideMap */);
return mLastInsets;
}
diff --git a/core/java/android/view/InsetsState.java b/core/java/android/view/InsetsState.java
index b66dd29e..bf377b0 100644
--- a/core/java/android/view/InsetsState.java
+++ b/core/java/android/view/InsetsState.java
@@ -16,6 +16,7 @@
package android.view;
+import static android.view.InsetsStateProto.DISPLAY_CUTOUT;
import static android.view.InsetsStateProto.DISPLAY_FRAME;
import static android.view.InsetsStateProto.SOURCES;
import static android.view.View.SYSTEM_UI_FLAG_LAYOUT_STABLE;
@@ -165,6 +166,10 @@
*/
private final Rect mDisplayFrame = new Rect();
+ /** The area cut from the display. */
+ private final DisplayCutout.ParcelableWrapper mDisplayCutout =
+ new DisplayCutout.ParcelableWrapper();
+
public InsetsState() {
}
@@ -186,7 +191,7 @@
* @return The calculated insets.
*/
public WindowInsets calculateInsets(Rect frame, @Nullable InsetsState ignoringVisibilityState,
- boolean isScreenRound, boolean alwaysConsumeSystemBars, DisplayCutout cutout,
+ boolean isScreenRound, boolean alwaysConsumeSystemBars,
int legacySoftInputMode, int legacyWindowFlags, int legacySystemUiFlags,
int windowType, @WindowConfiguration.WindowingMode int windowingMode,
@Nullable @InternalInsetsSide SparseIntArray typeSideMap) {
@@ -236,10 +241,31 @@
}
return new WindowInsets(typeInsetsMap, typeMaxInsetsMap, typeVisibilityMap, isScreenRound,
- alwaysConsumeSystemBars, cutout, compatInsetsTypes,
+ alwaysConsumeSystemBars, calculateRelativeCutout(frame), compatInsetsTypes,
(legacySystemUiFlags & SYSTEM_UI_FLAG_LAYOUT_STABLE) != 0);
}
+ private DisplayCutout calculateRelativeCutout(Rect frame) {
+ final DisplayCutout raw = mDisplayCutout.get();
+ if (mDisplayFrame.equals(frame)) {
+ return raw;
+ }
+ if (frame == null) {
+ return DisplayCutout.NO_CUTOUT;
+ }
+ final int insetLeft = frame.left - mDisplayFrame.left;
+ final int insetTop = frame.top - mDisplayFrame.top;
+ final int insetRight = mDisplayFrame.right - frame.right;
+ final int insetBottom = mDisplayFrame.bottom - frame.bottom;
+ if (insetLeft >= raw.getSafeInsetLeft()
+ && insetTop >= raw.getSafeInsetTop()
+ && insetRight >= raw.getSafeInsetRight()
+ && insetBottom >= raw.getSafeInsetBottom()) {
+ return DisplayCutout.NO_CUTOUT;
+ }
+ return raw.inset(insetLeft, insetTop, insetRight, insetBottom);
+ }
+
public Rect calculateInsets(Rect frame, @InsetsType int types, boolean ignoreVisibility) {
Insets insets = Insets.NONE;
for (int type = FIRST_TYPE; type <= LAST_TYPE; type++) {
@@ -392,15 +418,6 @@
return mSources[type];
}
- public boolean hasSources() {
- for (int i = 0; i < SIZE; i++) {
- if (mSources[i] != null) {
- return true;
- }
- }
- return false;
- }
-
/**
* Returns the source visibility or the default visibility if the source doesn't exist. This is
* useful if when treating this object as a request.
@@ -422,6 +439,14 @@
return mDisplayFrame;
}
+ public void setDisplayCutout(DisplayCutout cutout) {
+ mDisplayCutout.set(cutout);
+ }
+
+ public DisplayCutout getDisplayCutout() {
+ return mDisplayCutout.get();
+ }
+
/**
* Modifies the state of this class to exclude a certain type to make it ready for dispatching
* to the client.
@@ -452,6 +477,7 @@
*/
public void scale(float scale) {
mDisplayFrame.scale(scale);
+ mDisplayCutout.scale(scale);
for (int i = 0; i < SIZE; i++) {
final InsetsSource source = mSources[i];
if (source != null) {
@@ -470,6 +496,7 @@
public void set(InsetsState other, boolean copySources) {
mDisplayFrame.set(other.mDisplayFrame);
+ mDisplayCutout.set(other.mDisplayCutout);
if (copySources) {
for (int i = 0; i < SIZE; i++) {
InsetsSource source = other.mSources[i];
@@ -592,6 +619,7 @@
source.dumpDebug(proto, SOURCES);
}
mDisplayFrame.dumpDebug(proto, DISPLAY_FRAME);
+ mDisplayCutout.get().dumpDebug(proto, DISPLAY_CUTOUT);
proto.end(token);
}
@@ -669,7 +697,8 @@
InsetsState state = (InsetsState) o;
- if (!mDisplayFrame.equals(state.mDisplayFrame)) {
+ if (!mDisplayFrame.equals(state.mDisplayFrame)
+ || !mDisplayCutout.equals(state.mDisplayCutout)) {
return false;
}
for (int i = 0; i < SIZE; i++) {
@@ -681,7 +710,7 @@
if (source == null && otherSource == null) {
continue;
}
- if (source != null && otherSource == null || source == null && otherSource != null) {
+ if (source == null || otherSource == null) {
return false;
}
if (!otherSource.equals(source, excludeInvisibleImeFrames)) {
@@ -693,7 +722,7 @@
@Override
public int hashCode() {
- return Objects.hash(mDisplayFrame, Arrays.hashCode(mSources));
+ return Objects.hash(mDisplayFrame, mDisplayCutout, Arrays.hashCode(mSources));
}
public InsetsState(Parcel in) {
@@ -707,7 +736,8 @@
@Override
public void writeToParcel(Parcel dest, int flags) {
- dest.writeParcelable(mDisplayFrame, flags);
+ mDisplayFrame.writeToParcel(dest, flags);
+ mDisplayCutout.writeToParcel(dest, flags);
dest.writeParcelableArray(mSources, 0);
}
@@ -723,7 +753,8 @@
};
public void readFromParcel(Parcel in) {
- mDisplayFrame.set(in.readParcelable(null /* loader */));
+ mDisplayFrame.set(Rect.CREATOR.createFromParcel(in));
+ mDisplayCutout.set(DisplayCutout.ParcelableWrapper.CREATOR.createFromParcel(in));
mSources = in.readParcelableArray(null, InsetsSource.class);
}
@@ -738,6 +769,7 @@
}
return "InsetsState: {"
+ "mDisplayFrame=" + mDisplayFrame
+ + ", mDisplayCutout=" + mDisplayCutout
+ ", mSources= { " + joiner
+ " }";
}
diff --git a/core/java/android/view/View.java b/core/java/android/view/View.java
index 1d1c87d..24b71ab 100644
--- a/core/java/android/view/View.java
+++ b/core/java/android/view/View.java
@@ -29071,9 +29071,6 @@
*/
final Rect mCaptionInsets = new Rect();
- final DisplayCutout.ParcelableWrapper mDisplayCutout =
- new DisplayCutout.ParcelableWrapper(DisplayCutout.NO_CUTOUT);
-
/**
* In multi-window we force show the system bars. Because we don't want that the surface
* size changes in this mode, we instead have a flag whether the system bars sizes should
diff --git a/core/java/android/view/ViewRootImpl.java b/core/java/android/view/ViewRootImpl.java
index 0fc2d7a..7d309eb 100644
--- a/core/java/android/view/ViewRootImpl.java
+++ b/core/java/android/view/ViewRootImpl.java
@@ -42,7 +42,6 @@
import static android.view.ViewRootImplProto.IS_ANIMATING;
import static android.view.ViewRootImplProto.IS_DRAWING;
import static android.view.ViewRootImplProto.LAST_WINDOW_INSETS;
-import static android.view.ViewRootImplProto.PENDING_DISPLAY_CUTOUT;
import static android.view.ViewRootImplProto.REMOVED;
import static android.view.ViewRootImplProto.SCROLL_Y;
import static android.view.ViewRootImplProto.SOFT_INPUT_MODE;
@@ -573,8 +572,6 @@
final Rect mWinFrame; // frame given by window manager.
final Rect mPendingBackDropFrame = new Rect();
- final DisplayCutout.ParcelableWrapper mPendingDisplayCutout =
- new DisplayCutout.ParcelableWrapper(DisplayCutout.NO_CUTOUT);
boolean mPendingAlwaysConsumeSystemBars;
private final InsetsState mTempInsets = new InsetsState();
private final InsetsSourceControl[] mTempControls = new InsetsSourceControl[SIZE];
@@ -698,34 +695,33 @@
int localChanges;
}
- // If set, ViewRootImpl will request a callback from HWRender when it's ready to render the next
- // frame. This will allow VRI to call BLASTBufferQueue::setNextTransaction with
- // mRtBLASTSyncTransaction, so the next frame submitted will be added to the
- // mRtBLASTSyncTransaction instead of getting applied.
- private boolean mNextDrawUseBLASTSyncTransaction;
-
- // This is used to signal if the mRtBLASTSyncTransaction should be applied/merged. When true,
- // it indicates mRtBLASTSyncTransaction was sent to BLASTBufferQueue::setNextTransaction.
- // Therefore, in onFrameComplete, if mRtNextFrameReportConsumeWithBlast is true, that means
- // mRtBLASTSyncTransaction now contains the next buffer frame to be applied.
- private boolean mRtNextFrameReportedConsumeWithBlast;
-
- // Be very careful with the threading here. This is used from a thread pool generated by the
- // render thread. Therefore, it needs to be locked when updating from the thread pool since
- // multiple threads can be accessing it. It does not need to be locked when applied or merged
- // since that can only happen from the frame complete callback after the other callbacks have
- // been invoked.
+ /**
+ * This is only used when the UI thread is paused due to {@link #mNextDrawUseBlastSync} being
+ * set. Specifically, it's only used when calling
+ * {@link BLASTBufferQueue#setNextTransaction(Transaction)} and then merged with
+ * {@link #mSurfaceChangedTransaction}. It doesn't need to be thread safe since it's only
+ * accessed when the UI thread is paused.
+ */
private final SurfaceControl.Transaction mRtBLASTSyncTransaction =
new SurfaceControl.Transaction();
- // Keeps track of whether the WM requested us to use BLAST Sync when calling relayout.
- // We use this to make sure we don't send the WM transactions from an internal BLAST sync
- // (e.g. SurfaceView)
- private boolean mSendNextFrameToWm = false;
+ /**
+ * Keeps track of whether the WM requested to use BLAST Sync when calling relayout. When set,
+ * we pause the UI thread to ensure we don't get overlapping requests. We then send a
+ * transaction to {@link BLASTBufferQueue#setNextTransaction(Transaction)}, which is then sent
+ * back to WM to synchronize.
+ *
+ * This flag is set to false only after the synchronized transaction that contains the buffer
+ * has been sent to SurfaceFlinger.
+ */
+ private boolean mNextDrawUseBlastSync = false;
- // Keeps track of whether a traverse was triggered while the UI thread was paused. This can
- // occur when the client is waiting on another process to submit the transaction that contains
- // the buffer. The UI thread needs to wait on the callback before it can submit another buffer.
+ /**
+ * Keeps track of whether a traverse was triggered while the UI thread was paused. This can
+ * occur when the client is waiting on another process to submit the transaction that
+ * contains the buffer. The UI thread needs to wait on the callback before it can submit
+ * another buffer.
+ */
private boolean mRequestedTraverseWhilePaused = false;
private HashSet<ScrollCaptureCallback> mRootScrollCaptureCallbacks;
@@ -1062,8 +1058,7 @@
res = mWindowSession.addToDisplayAsUser(mWindow, mWindowAttributes,
getHostVisibility(), mDisplay.getDisplayId(), userId,
mInsetsController.getRequestedVisibility(), mTmpFrames.frame,
- mAttachInfo.mDisplayCutout, inputChannel,
- mTempInsets, mTempControls);
+ inputChannel, mTempInsets, mTempControls);
if (mTranslator != null) {
mTranslator.translateRectInScreenToAppWindow(mTmpFrames.frame);
mTranslator.translateInsetsStateInScreenToAppWindow(mTempInsets);
@@ -1084,7 +1079,6 @@
}
}
- mPendingDisplayCutout.set(mAttachInfo.mDisplayCutout);
mAttachInfo.mAlwaysConsumeSystemBars =
(res & WindowManagerGlobal.ADD_FLAG_ALWAYS_CONSUME_SYSTEM_BARS) != 0;
mPendingAlwaysConsumeSystemBars = mAttachInfo.mAlwaysConsumeSystemBars;
@@ -1395,7 +1389,8 @@
return mLocation;
}
- void setLayoutParams(WindowManager.LayoutParams attrs, boolean newView) {
+ @VisibleForTesting
+ public void setLayoutParams(WindowManager.LayoutParams attrs, boolean newView) {
synchronized (this) {
final int oldInsetLeft = mWindowAttributes.surfaceInsets.left;
final int oldInsetTop = mWindowAttributes.surfaceInsets.top;
@@ -1417,13 +1412,15 @@
final int compatibleWindowFlag = mWindowAttributes.privateFlags
& WindowManager.LayoutParams.PRIVATE_FLAG_COMPATIBLE_WINDOW;
- // Transfer over system UI visibility values as they carry current state.
- attrs.systemUiVisibility = mWindowAttributes.systemUiVisibility;
- attrs.subtreeSystemUiVisibility = mWindowAttributes.subtreeSystemUiVisibility;
+ // Preserve system UI visibility.
+ final int systemUiVisibility = mWindowAttributes.systemUiVisibility;
+ final int subtreeSystemUiVisibility = mWindowAttributes.subtreeSystemUiVisibility;
- // Transfer over appearance and behavior values as they carry current state.
- attrs.insetsFlags.appearance = mWindowAttributes.insetsFlags.appearance;
- attrs.insetsFlags.behavior = mWindowAttributes.insetsFlags.behavior;
+ // Preserve appearance and behavior.
+ final int appearance = mWindowAttributes.insetsFlags.appearance;
+ final int behavior = mWindowAttributes.insetsFlags.behavior;
+ final int appearanceAndBehaviorPrivateFlags = mWindowAttributes.privateFlags
+ & (PRIVATE_FLAG_APPEARANCE_CONTROLLED | PRIVATE_FLAG_BEHAVIOR_CONTROLLED);
final int changes = mWindowAttributes.copyFrom(attrs);
if ((changes & WindowManager.LayoutParams.TRANSLUCENT_FLAGS_CHANGED) != 0) {
@@ -1437,10 +1434,15 @@
if (mWindowAttributes.packageName == null) {
mWindowAttributes.packageName = mBasePackageName;
}
- mWindowAttributes.privateFlags |= compatibleWindowFlag;
- mWindowAttributes.privateFlags |=
- WindowManager.LayoutParams.PRIVATE_FLAG_USE_BLAST;
+ // Restore preserved flags.
+ mWindowAttributes.systemUiVisibility = systemUiVisibility;
+ mWindowAttributes.subtreeSystemUiVisibility = subtreeSystemUiVisibility;
+ mWindowAttributes.insetsFlags.appearance = appearance;
+ mWindowAttributes.insetsFlags.behavior = behavior;
+ mWindowAttributes.privateFlags |= compatibleWindowFlag
+ | appearanceAndBehaviorPrivateFlags
+ | WindowManager.LayoutParams.PRIVATE_FLAG_USE_BLAST;
if (mWindowAttributes.preservePreviousSurfaceInsets) {
// Restore old surface insets.
@@ -1505,15 +1507,13 @@
final boolean forceNextWindowRelayout = args.argi1 != 0;
final int displayId = args.argi3;
final Rect backdropFrame = frames.backdropFrame;
- final DisplayCutout displayCutout = frames.displayCutout.get();
final boolean frameChanged = !mWinFrame.equals(frames.frame);
- final boolean cutoutChanged = !mPendingDisplayCutout.get().equals(displayCutout);
final boolean backdropFrameChanged = !mPendingBackDropFrame.equals(backdropFrame);
final boolean configChanged = !mLastReportedMergedConfiguration.equals(mergedConfiguration);
final boolean displayChanged = mDisplay.getDisplayId() != displayId;
- if (msg == MSG_RESIZED && !frameChanged && !cutoutChanged && !backdropFrameChanged
- && !configChanged && !displayChanged && !forceNextWindowRelayout) {
+ if (msg == MSG_RESIZED && !frameChanged && !backdropFrameChanged && !configChanged
+ && !displayChanged && !forceNextWindowRelayout) {
return;
}
@@ -1528,16 +1528,15 @@
setFrame(frames.frame);
mTmpFrames.displayFrame.set(frames.displayFrame);
- mPendingDisplayCutout.set(displayCutout);
mPendingBackDropFrame.set(backdropFrame);
mForceNextWindowRelayout = forceNextWindowRelayout;
mPendingAlwaysConsumeSystemBars = args.argi2 != 0;
- if (msg == MSG_RESIZED_REPORT && !mSendNextFrameToWm) {
+ if (msg == MSG_RESIZED_REPORT && !mNextDrawUseBlastSync) {
reportNextDraw();
}
- if (mView != null && (frameChanged || cutoutChanged || configChanged)) {
+ if (mView != null && (frameChanged || configChanged)) {
forceLayout(mView);
}
requestLayout();
@@ -2337,8 +2336,7 @@
final Configuration config = mContext.getResources().getConfiguration();
mLastWindowInsets = mInsetsController.calculateInsets(
config.isScreenRound(), mAttachInfo.mAlwaysConsumeSystemBars,
- mPendingDisplayCutout.get(), mWindowAttributes.type,
- config.windowConfiguration.getWindowingMode(),
+ mWindowAttributes.type, config.windowConfiguration.getWindowingMode(),
mWindowAttributes.softInputMode, mWindowAttributes.flags,
(mWindowAttributes.systemUiVisibility
| mWindowAttributes.subtreeSystemUiVisibility));
@@ -2424,7 +2422,7 @@
//
// When the callback is invoked, it will trigger a traversal request if
// mRequestedTraverseWhilePaused is set so there's no need to attempt a retry here.
- if (mSendNextFrameToWm) {
+ if (mNextDrawUseBlastSync) {
if (DEBUG_BLAST) {
Log.w(mTag, "Can't perform draw while waiting for a transaction complete");
}
@@ -2538,8 +2536,6 @@
// Execute enqueued actions on every traversal in case a detached view enqueued an action
getRunQueue().executeActions(mAttachInfo.mHandler);
- boolean cutoutChanged = false;
-
boolean layoutRequested = mLayoutRequested && (!mStopped || mReportNextDraw);
if (layoutRequested) {
@@ -2551,9 +2547,6 @@
mAttachInfo.mInTouchMode = !mAddedTouchMode;
ensureTouchModeLocally(mAddedTouchMode);
} else {
- if (!mPendingDisplayCutout.equals(mAttachInfo.mDisplayCutout)) {
- cutoutChanged = true;
- }
if (lp.width == ViewGroup.LayoutParams.WRAP_CONTENT
|| lp.height == ViewGroup.LayoutParams.WRAP_CONTENT) {
windowSizeMayChange = true;
@@ -2679,7 +2672,7 @@
}
}
- if (mFirst || windowShouldResize || viewVisibilityChanged || cutoutChanged || params != null
+ if (mFirst || windowShouldResize || viewVisibilityChanged || params != null
|| mForceNextWindowRelayout) {
mForceNextWindowRelayout = false;
@@ -2719,7 +2712,6 @@
relayoutResult = relayoutWindow(params, viewVisibility, insetsPending);
if (DEBUG_LAYOUT) Log.v(mTag, "relayout: frame=" + frame.toShortString()
- + " cutout=" + mPendingDisplayCutout.get().toString()
+ " surface=" + mSurface);
// If the pending {@link MergedConfiguration} handed back from
@@ -2735,7 +2727,6 @@
updatedConfiguration = true;
}
- cutoutChanged = !mPendingDisplayCutout.equals(mAttachInfo.mDisplayCutout);
surfaceSizeChanged = false;
if (!mLastSurfaceSize.equals(mSurfaceSize)) {
surfaceSizeChanged = true;
@@ -2759,14 +2750,6 @@
mSurfaceSequenceId++;
}
- if (cutoutChanged) {
- mAttachInfo.mDisplayCutout.set(mPendingDisplayCutout);
- if (DEBUG_LAYOUT) {
- Log.v(mTag, "DisplayCutout changing to: " + mAttachInfo.mDisplayCutout);
- }
- // Need to relayout with content insets.
- dispatchApplyInsets = true;
- }
if (alwaysConsumeSystemBarsChanged) {
mAttachInfo.mAlwaysConsumeSystemBars = mPendingAlwaysConsumeSystemBars;
dispatchApplyInsets = true;
@@ -3176,8 +3159,7 @@
Log.d(mTag, "Relayout called with blastSync");
}
reportNextDraw();
- setUseBLASTSyncTransaction();
- mSendNextFrameToWm = true;
+ mNextDrawUseBlastSync = true;
}
boolean cancelDraw = mAttachInfo.mTreeObserver.dispatchOnPreDraw() || !isViewVisible;
@@ -3868,19 +3850,19 @@
private HardwareRenderer.FrameCompleteCallback createFrameCompleteCallback(Handler handler,
boolean reportNextDraw, ArrayList<Runnable> commitCallbacks) {
return frameNr -> {
- mBlurRegionAggregator.dispatchBlurTransactionIfNeeded(frameNr);
-
if (DEBUG_BLAST) {
Log.d(mTag, "Received frameCompleteCallback frameNum=" + frameNr);
}
- // Use a new transaction here since mRtBLASTSyncTransaction can only be accessed by
- // the render thread and mSurfaceChangedTransaction can only be accessed by the UI
- // thread. The temporary transaction is used so mRtBLASTSyncTransaction can be merged
- // with mSurfaceChangedTransaction without synchronization issues.
- final Transaction t = new Transaction();
- finishBLASTSyncOnRT(!mSendNextFrameToWm, t);
+
handler.postAtFrontOfQueue(() -> {
- mSurfaceChangedTransaction.merge(t);
+ if (mNextDrawUseBlastSync) {
+ // We don't need to synchronize mRtBLASTSyncTransaction here since we're
+ // guaranteed that this is called after onFrameDraw and mNextDrawUseBlastSync
+ // is only true when the UI thread is paused. Therefore, no one should be
+ // modifying this object until the next vsync.
+ mSurfaceChangedTransaction.merge(mRtBLASTSyncTransaction);
+ }
+
if (reportNextDraw) {
// TODO: Use the frame number
pendingDrawFinished();
@@ -3902,13 +3884,12 @@
ArrayList<Runnable> commitCallbacks = mAttachInfo.mTreeObserver
.captureFrameCommitCallbacks();
final boolean needFrameCompleteCallback =
- mNextDrawUseBLASTSyncTransaction || mReportNextDraw
- || (commitCallbacks != null && commitCallbacks.size() > 0)
- || mBlurRegionAggregator.hasRegions();
+ mNextDrawUseBlastSync || mReportNextDraw
+ || (commitCallbacks != null && commitCallbacks.size() > 0);
if (needFrameCompleteCallback) {
if (DEBUG_BLAST) {
Log.d(mTag, "Creating frameCompleteCallback"
- + " mNextDrawUseBLASTSyncTransaction=" + mNextDrawUseBLASTSyncTransaction
+ + " mNextDrawUseBlastSync=" + mNextDrawUseBlastSync
+ " mReportNextDraw=" + mReportNextDraw
+ " commitCallbacks size="
+ (commitCallbacks == null ? 0 : commitCallbacks.size()));
@@ -3921,75 +3902,70 @@
return false;
}
- /**
- * The callback will run on a worker thread pool from the render thread.
- */
- private HardwareRenderer.FrameDrawingCallback createFrameDrawingCallback(
- boolean addTransactionComplete) {
- return frame -> {
+ private void addFrameCallbackIfNeeded() {
+ boolean nextDrawUseBlastSync = mNextDrawUseBlastSync;
+ boolean hasBlur = mBlurRegionAggregator.hasRegions();
+ boolean reportNextDraw = mReportNextDraw;
+
+ if (!nextDrawUseBlastSync && !reportNextDraw && !hasBlur) {
+ return;
+ }
+
+ if (DEBUG_BLAST) {
+ Log.d(mTag, "Creating frameDrawingCallback"
+ + " nextDrawUseBlastSync=" + nextDrawUseBlastSync
+ + " reportNextDraw=" + reportNextDraw
+ + " hasBlur=" + hasBlur);
+ }
+
+ // The callback will run on a worker thread pool from the render thread.
+ HardwareRenderer.FrameDrawingCallback frameDrawingCallback = frame -> {
if (DEBUG_BLAST) {
Log.d(mTag, "Received frameDrawingCallback frameNum=" + frame + "."
- + " Creating transactionCompleteCallback=" + addTransactionComplete);
+ + " Creating transactionCompleteCallback=" + nextDrawUseBlastSync);
}
- mRtNextFrameReportedConsumeWithBlast = true;
+
+ if (hasBlur) {
+ mBlurRegionAggregator.dispatchBlurTransactionIfNeeded(frame);
+ }
+
if (mBlastBufferQueue == null) {
return;
}
- // We don't need to synchronize mRtBLASTSyncTransaction here since it's not
- // being modified and only sent to BlastBufferQueue.
- mBlastBufferQueue.setNextTransaction(mRtBLASTSyncTransaction);
- if (!addTransactionComplete) {
- return;
- }
+ if (nextDrawUseBlastSync) {
+ // Frame callbacks will always occur after submitting draw requests and before
+ // the draw actually occurs. This will ensure that we set the next transaction
+ // for the frame that's about to get drawn and not on a previous frame that.
- mBlastBufferQueue.setTransactionCompleteCallback(frame, frameNumber -> {
- if (DEBUG_BLAST) {
- Log.d(mTag, "Received transactionCompleteCallback frameNum=" + frame);
- }
- mHandler.postAtFrontOfQueue(() -> {
- mSendNextFrameToWm = false;
+ // We don't need to synchronize mRtBLASTSyncTransaction here since it's not
+ // being modified and only sent to BlastBufferQueue.
+ mBlastBufferQueue.setNextTransaction(mRtBLASTSyncTransaction);
+
+ mBlastBufferQueue.setTransactionCompleteCallback(frame, frameNumber -> {
if (DEBUG_BLAST) {
- Log.d(mTag, "Scheduling a traversal=" + mRequestedTraverseWhilePaused
- + " due to a previous skipped traversal.");
+ Log.d(mTag, "Received transactionCompleteCallback frameNum=" + frame);
}
- if (mRequestedTraverseWhilePaused) {
- mRequestedTraverseWhilePaused = false;
- scheduleTraversals();
- }
+ mHandler.postAtFrontOfQueue(() -> {
+ mNextDrawUseBlastSync = false;
+ if (DEBUG_BLAST) {
+ Log.d(mTag, "Scheduling a traversal=" + mRequestedTraverseWhilePaused
+ + " due to a previous skipped traversal.");
+ }
+ if (mRequestedTraverseWhilePaused) {
+ mRequestedTraverseWhilePaused = false;
+ scheduleTraversals();
+ }
+ });
});
- });
- };
- }
-
- private void addFrameCallbackIfNeeded() {
- if (DEBUG_BLAST) {
- if (mNextDrawUseBLASTSyncTransaction || mReportNextDraw) {
- Log.d(mTag, "Creating frameDrawingCallback mNextDrawUseBLASTSyncTransaction="
- + mNextDrawUseBLASTSyncTransaction + " mReportNextDraw=" + mReportNextDraw);
+ } else if (reportNextDraw) {
+ // If we need to report next draw, wait for adapter to flush its shadow queue
+ // by processing previously queued buffers so that we can submit the
+ // transaction a timely manner.
+ mBlastBufferQueue.flushShadowQueue();
}
- }
-
- if (mNextDrawUseBLASTSyncTransaction) {
- // Frame callbacks will always occur after submitting draw requests and before
- // the draw actually occurs. This will ensure that we set the next transaction
- // for the frame that's about to get drawn and not on a previous frame that.
- //
- // This is thread safe since mRtNextFrameReportConsumeWithBlast will only be
- // modified in onFrameDraw and then again in onFrameComplete. This is to ensure the
- // next frame completed should be reported with the blast sync transaction.
- registerRtFrameCallback(createFrameDrawingCallback(mSendNextFrameToWm));
- mNextDrawUseBLASTSyncTransaction = false;
- } else if (mReportNextDraw) {
- registerRtFrameCallback(frame -> {
- if (mBlastBufferQueue != null) {
- // If we need to report next draw, wait for adapter to flush its shadow queue
- // by processing previously queued buffers so that we can submit the
- // transaction a timely manner.
- mBlastBufferQueue.flushShadowQueue();
- }
- });
- }
+ };
+ registerRtFrameCallback(frameDrawingCallback);
}
private void performDraw() {
@@ -4000,7 +3976,7 @@
}
final boolean fullRedrawNeeded =
- mFullRedrawNeeded || mReportNextDraw || mNextDrawUseBLASTSyncTransaction;
+ mFullRedrawNeeded || mReportNextDraw || mNextDrawUseBlastSync;
mFullRedrawNeeded = false;
mIsDrawing = true;
@@ -7595,7 +7571,6 @@
insetsPending ? WindowManagerGlobal.RELAYOUT_INSETS_PENDING : 0, frameNumber,
mTmpFrames, mPendingMergedConfiguration, mSurfaceControl, mTempInsets,
mTempControls, mSurfaceSize);
- mPendingDisplayCutout.set(mTmpFrames.displayCutout);
mPendingBackDropFrame.set(mTmpFrames.backdropFrame);
if (mSurfaceControl.isValid()) {
if (!useBLAST()) {
@@ -7756,7 +7731,6 @@
proto.write(IS_DRAWING, mIsDrawing);
proto.write(ADDED, mAdded);
mWinFrame.dumpDebug(proto, WIN_FRAME);
- mPendingDisplayCutout.get().dumpDebug(proto, PENDING_DISPLAY_CUTOUT);
proto.write(LAST_WINDOW_INSETS, Objects.toString(mLastWindowInsets));
proto.write(SOFT_INPUT_MODE, InputMethodDebug.softInputModeToString(mSoftInputMode));
proto.write(SCROLL_Y, mScrollY);
@@ -10023,42 +9997,6 @@
}
}
- void setUseBLASTSyncTransaction() {
- mNextDrawUseBLASTSyncTransaction = true;
- }
-
- /**
- * This should only be called from the render thread.
- */
- private void finishBLASTSyncOnRT(boolean apply, Transaction t) {
- // This is safe to modify on the render thread since the only other place it's modified
- // is on the UI thread when the render thread is paused.
- if (mRtNextFrameReportedConsumeWithBlast) {
- mRtNextFrameReportedConsumeWithBlast = false;
-
- // We don't need to synchronize mRtBLASTSyncTransaction here we're guaranteed that this
- // is called after all onFrameDraw and after callbacks to PositionUpdateListener.
- // Therefore, no one should be modifying this object until the next vsync.
- if (apply) {
- mRtBLASTSyncTransaction.apply();
- } else {
- t.merge(mRtBLASTSyncTransaction);
- }
-
- // There's potential for the frame callback to get called even if nothing was drawn.
- // When that occurs, we remove the transaction sent to BBQ since the draw we were
- // waiting on will not happen. We can apply the transaction here but it will not contain
- // a buffer since nothing new was drawn.
- //
- // This is mainly for the case when the SurfaceView has changed and wants to synchronize
- // with the main window. If the main window doesn't need to draw anything, we can just
- // apply the transaction without the new buffer from the main window.
- if (mBlastBufferQueue != null) {
- mBlastBufferQueue.setNextTransaction(null);
- }
- }
- }
-
/**
* Sends a list of blur regions to SurfaceFlinger, tagged with a frame.
*
@@ -10070,14 +10008,14 @@
if (!surfaceControl.isValid()) {
return;
}
- if (useBLAST()) {
- synchronized (getBlastTransactionLock()) {
- getBLASTSyncTransaction().setBlurRegions(surfaceControl, regionCopy);
- }
+
+ SurfaceControl.Transaction transaction = new SurfaceControl.Transaction();
+ transaction.setBlurRegions(surfaceControl, regionCopy);
+
+ if (useBLAST() && mBlastBufferQueue != null) {
+ mBlastBufferQueue.mergeWithNextTransaction(transaction, frameNumber);
} else {
- SurfaceControl.Transaction transaction = new SurfaceControl.Transaction();
- transaction.setBlurRegions(surfaceControl, regionCopy);
- transaction.deferTransactionUntil(surfaceControl, getSurfaceControl(), frameNumber);
+ transaction.deferTransactionUntil(surfaceControl, surfaceControl, frameNumber);
transaction.apply();
}
}
@@ -10089,14 +10027,6 @@
return mBlurRegionAggregator.createBackgroundBlurDrawable(mContext);
}
- SurfaceControl.Transaction getBLASTSyncTransaction() {
- return mRtBLASTSyncTransaction;
- }
-
- Object getBlastTransactionLock() {
- return mRtBLASTSyncTransaction;
- }
-
@Override
public void onDescendantUnbufferedRequested() {
mUnbufferedInputSource = mView.mUnbufferedInputSource;
diff --git a/core/java/android/view/WindowManagerImpl.java b/core/java/android/view/WindowManagerImpl.java
index 3384bbe..391e55a 100644
--- a/core/java/android/view/WindowManagerImpl.java
+++ b/core/java/android/view/WindowManagerImpl.java
@@ -262,18 +262,15 @@
private WindowInsets getWindowInsetsFromServer(WindowManager.LayoutParams attrs, Rect bounds) {
try {
- final DisplayCutout.ParcelableWrapper displayCutout =
- new DisplayCutout.ParcelableWrapper();
final InsetsState insetsState = new InsetsState();
final boolean alwaysConsumeSystemBars = WindowManagerGlobal.getWindowManagerService()
- .getWindowInsets(attrs, mContext.getDisplayId(), displayCutout, insetsState);
+ .getWindowInsets(attrs, mContext.getDisplayId(), insetsState);
final Configuration config = mContext.getResources().getConfiguration();
final boolean isScreenRound = config.isScreenRound();
final int windowingMode = config.windowConfiguration.getWindowingMode();
return insetsState.calculateInsets(bounds, null /* ignoringVisibilityState*/,
- isScreenRound, alwaysConsumeSystemBars, displayCutout.get(),
- SOFT_INPUT_ADJUST_NOTHING, attrs.flags, SYSTEM_UI_FLAG_VISIBLE, attrs.type,
- windowingMode, null /* typeSideMap */);
+ isScreenRound, alwaysConsumeSystemBars, SOFT_INPUT_ADJUST_NOTHING, attrs.flags,
+ SYSTEM_UI_FLAG_VISIBLE, attrs.type, windowingMode, null /* typeSideMap */);
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
diff --git a/core/java/android/view/WindowlessWindowManager.java b/core/java/android/view/WindowlessWindowManager.java
index 149338c..dd56c15 100644
--- a/core/java/android/view/WindowlessWindowManager.java
+++ b/core/java/android/view/WindowlessWindowManager.java
@@ -136,8 +136,8 @@
@Override
public int addToDisplay(IWindow window, WindowManager.LayoutParams attrs,
int viewVisibility, int displayId, InsetsState requestedVisibility, Rect outFrame,
- DisplayCutout.ParcelableWrapper outDisplayCutout, InputChannel outInputChannel,
- InsetsState outInsetsState, InsetsSourceControl[] outActiveControls) {
+ InputChannel outInputChannel, InsetsState outInsetsState,
+ InsetsSourceControl[] outActiveControls) {
final SurfaceControl.Builder b = new SurfaceControl.Builder(mSurfaceSession)
.setFormat(attrs.format)
.setBufferSize(getSurfaceWidth(attrs), getSurfaceHeight(attrs))
@@ -171,11 +171,10 @@
@Override
public int addToDisplayAsUser(IWindow window, WindowManager.LayoutParams attrs,
int viewVisibility, int displayId, int userId, InsetsState requestedVisibility,
- Rect outFrame, DisplayCutout.ParcelableWrapper outDisplayCutout,
- InputChannel outInputChannel, InsetsState outInsetsState,
+ Rect outFrame, InputChannel outInputChannel, InsetsState outInsetsState,
InsetsSourceControl[] outActiveControls) {
return addToDisplay(window, attrs, viewVisibility, displayId, requestedVisibility,
- outFrame, outDisplayCutout, outInputChannel, outInsetsState, outActiveControls);
+ outFrame, outInputChannel, outInsetsState, outActiveControls);
}
@Override
diff --git a/core/java/android/window/ClientWindowFrames.java b/core/java/android/window/ClientWindowFrames.java
index 5d7025b..e22a5eb 100644
--- a/core/java/android/window/ClientWindowFrames.java
+++ b/core/java/android/window/ClientWindowFrames.java
@@ -20,7 +20,6 @@
import android.graphics.Rect;
import android.os.Parcel;
import android.os.Parcelable;
-import android.view.DisplayCutout;
/**
* The window frame container class used by client side for layout.
@@ -39,28 +38,22 @@
/** The background area while the window is resizing. */
public final @NonNull Rect backdropFrame;
- /** The area cut from the display. */
- public final @NonNull DisplayCutout.ParcelableWrapper displayCutout;
-
public ClientWindowFrames() {
frame = new Rect();
displayFrame = new Rect();
backdropFrame = new Rect();
- displayCutout = new DisplayCutout.ParcelableWrapper();
}
public ClientWindowFrames(ClientWindowFrames other) {
frame = new Rect(other.frame);
displayFrame = new Rect(other.displayFrame);
backdropFrame = new Rect(other.backdropFrame);
- displayCutout = new DisplayCutout.ParcelableWrapper(other.displayCutout.get());
}
private ClientWindowFrames(Parcel in) {
frame = Rect.CREATOR.createFromParcel(in);
displayFrame = Rect.CREATOR.createFromParcel(in);
backdropFrame = Rect.CREATOR.createFromParcel(in);
- displayCutout = DisplayCutout.ParcelableWrapper.CREATOR.createFromParcel(in);
}
/** Needed for AIDL out parameters. */
@@ -68,7 +61,6 @@
frame.set(Rect.CREATOR.createFromParcel(in));
displayFrame.set(Rect.CREATOR.createFromParcel(in));
backdropFrame.set(Rect.CREATOR.createFromParcel(in));
- displayCutout.set(DisplayCutout.ParcelableWrapper.CREATOR.createFromParcel(in));
}
@Override
@@ -76,7 +68,6 @@
frame.writeToParcel(dest, flags);
displayFrame.writeToParcel(dest, flags);
backdropFrame.writeToParcel(dest, flags);
- displayCutout.writeToParcel(dest, flags);
}
@Override
@@ -84,8 +75,7 @@
final StringBuilder sb = new StringBuilder(32);
return "ClientWindowFrames{frame=" + frame.toShortString(sb)
+ " display=" + displayFrame.toShortString(sb)
- + " backdrop=" + backdropFrame.toShortString(sb)
- + " cutout=" + displayCutout + "}";
+ + " backdrop=" + backdropFrame.toShortString(sb) + "}";
}
@Override
diff --git a/core/java/com/android/internal/app/ChooserFlags.java b/core/java/com/android/internal/app/ChooserFlags.java
index 3e26679..1a93f1b 100644
--- a/core/java/com/android/internal/app/ChooserFlags.java
+++ b/core/java/com/android/internal/app/ChooserFlags.java
@@ -33,7 +33,7 @@
*/
public static final boolean USE_SERVICE_TARGETS_FOR_DIRECT_TARGETS =
DeviceConfig.getBoolean(DeviceConfig.NAMESPACE_SYSTEMUI,
- SystemUiDeviceConfigFlags.SHARE_USE_SERVICE_TARGETS, true);
+ SystemUiDeviceConfigFlags.SHARE_USE_SERVICE_TARGETS, false);
/**
* Whether to use {@link AppPredictionManager} to query for direct share targets (as opposed to
diff --git a/core/java/com/android/internal/app/NetInitiatedActivity.java b/core/java/com/android/internal/app/NetInitiatedActivity.java
index 56ec87c..375e503 100644
--- a/core/java/com/android/internal/app/NetInitiatedActivity.java
+++ b/core/java/com/android/internal/app/NetInitiatedActivity.java
@@ -17,18 +17,14 @@
package com.android.internal.app;
import android.app.AlertDialog;
-import android.compat.annotation.UnsupportedAppUsage;
-import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.DialogInterface;
import android.content.Intent;
-import android.content.IntentFilter;
import android.location.LocationManagerInternal;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.util.Log;
-import android.widget.Toast;
import com.android.internal.R;
import com.android.internal.location.GpsNetInitiatedHandler;
@@ -43,7 +39,6 @@
private static final String TAG = "NetInitiatedActivity";
private static final boolean DEBUG = true;
- private static final boolean VERBOSE = false;
private static final int POSITIVE_BUTTON = AlertDialog.BUTTON_POSITIVE;
private static final int NEGATIVE_BUTTON = AlertDialog.BUTTON_NEGATIVE;
@@ -55,17 +50,6 @@
private int default_response = -1;
private int default_response_timeout = 6;
- /** Used to detect when NI request is received */
- private BroadcastReceiver mNetInitiatedReceiver = new BroadcastReceiver() {
- @Override
- public void onReceive(Context context, Intent intent) {
- if (DEBUG) Log.d(TAG, "NetInitiatedReceiver onReceive: " + intent.getAction());
- if (intent.getAction() == GpsNetInitiatedHandler.ACTION_NI_VERIFY) {
- handleNIVerify(intent);
- }
- }
- };
-
private final Handler mHandler = new Handler() {
public void handleMessage(Message msg) {
switch (msg.what) {
@@ -109,14 +93,12 @@
protected void onResume() {
super.onResume();
if (DEBUG) Log.d(TAG, "onResume");
- registerReceiver(mNetInitiatedReceiver, new IntentFilter(GpsNetInitiatedHandler.ACTION_NI_VERIFY));
}
@Override
protected void onPause() {
super.onPause();
if (DEBUG) Log.d(TAG, "onPause");
- unregisterReceiver(mNetInitiatedReceiver);
}
/**
@@ -141,17 +123,4 @@
LocationManagerInternal lm = LocalServices.getService(LocationManagerInternal.class);
lm.sendNiResponse(notificationId, response);
}
-
- @UnsupportedAppUsage
- private void handleNIVerify(Intent intent) {
- int notifId = intent.getIntExtra(GpsNetInitiatedHandler.NI_INTENT_KEY_NOTIF_ID, -1);
- notificationId = notifId;
-
- if (DEBUG) Log.d(TAG, "handleNIVerify action: " + intent.getAction());
- }
-
- private void showNIError() {
- Toast.makeText(this, "NI error" /* com.android.internal.R.string.usb_storage_error_message */,
- Toast.LENGTH_LONG).show();
- }
}
diff --git a/core/java/com/android/internal/os/BatteryStatsImpl.java b/core/java/com/android/internal/os/BatteryStatsImpl.java
index 0fa0df6..93dff9f 100644
--- a/core/java/com/android/internal/os/BatteryStatsImpl.java
+++ b/core/java/com/android/internal/os/BatteryStatsImpl.java
@@ -8648,6 +8648,15 @@
}
}
+ @Override
+ public long getScreenOnEnergy() {
+ if (mUidMeasuredEnergyStats == null) {
+ return ENERGY_DATA_UNAVAILABLE;
+ }
+ return mUidMeasuredEnergyStats.getAccumulatedBucketEnergy(
+ MeasuredEnergyStats.ENERGY_BUCKET_SCREEN_ON);
+ }
+
void initNetworkActivityLocked() {
detachIfNotNull(mNetworkByteActivityCounters);
mNetworkByteActivityCounters = new LongSamplingCounter[NUM_NETWORK_ACTIVITY_TYPES];
diff --git a/core/proto/android/server/windowmanagerservice.proto b/core/proto/android/server/windowmanagerservice.proto
index c4c007d..610e0e0 100644
--- a/core/proto/android/server/windowmanagerservice.proto
+++ b/core/proto/android/server/windowmanagerservice.proto
@@ -509,7 +509,7 @@
optional .android.graphics.RectProto overscan_frame = 7 [deprecated=true];
optional .android.graphics.RectProto parent_frame = 8;
optional .android.graphics.RectProto visible_frame = 9 [deprecated=true];
- optional .android.view.DisplayCutoutProto cutout = 10;
+ optional .android.view.DisplayCutoutProto cutout = 10 [deprecated=true];
optional .android.graphics.RectProto content_insets = 11 [deprecated=true];
optional .android.graphics.RectProto overscan_insets = 12 [deprecated=true];
optional .android.graphics.RectProto visible_insets = 13 [deprecated=true];
diff --git a/core/proto/android/view/insetsstate.proto b/core/proto/android/view/insetsstate.proto
index 9e9933d..1cab982 100644
--- a/core/proto/android/view/insetsstate.proto
+++ b/core/proto/android/view/insetsstate.proto
@@ -16,8 +16,9 @@
syntax = "proto2";
-import "frameworks/base/core/proto/android/view/insetssource.proto";
import "frameworks/base/core/proto/android/graphics/rect.proto";
+import "frameworks/base/core/proto/android/view/displaycutout.proto";
+import "frameworks/base/core/proto/android/view/insetssource.proto";
package android.view;
@@ -29,4 +30,5 @@
message InsetsStateProto {
repeated InsetsSourceProto sources = 1;
optional .android.graphics.RectProto display_frame = 2;
-}
\ No newline at end of file
+ optional DisplayCutoutProto display_cutout = 3;
+}
diff --git a/core/proto/android/view/viewrootimpl.proto b/core/proto/android/view/viewrootimpl.proto
index 0abe5e06..181b2bb 100644
--- a/core/proto/android/view/viewrootimpl.proto
+++ b/core/proto/android/view/viewrootimpl.proto
@@ -38,7 +38,7 @@
optional bool is_drawing = 8;
optional bool added = 9;
optional .android.graphics.RectProto win_frame = 10;
- optional DisplayCutoutProto pending_display_cutout = 11;
+ optional DisplayCutoutProto pending_display_cutout = 11 [deprecated=true];
optional string last_window_insets = 12;
optional string soft_input_mode = 13;
optional int32 scroll_y = 14;
diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml
index 60e0ae8..8682fea 100644
--- a/core/res/AndroidManifest.xml
+++ b/core/res/AndroidManifest.xml
@@ -1591,13 +1591,31 @@
<permission android:name="android.permission.INSTALL_LOCATION_PROVIDER"
android:protectionLevel="signature|privileged" />
- <!-- @SystemApi @hide Allows an application to install a LocationTimeZoneProvider into the
- LocationTimeZoneProviderManager.
+ <!-- @SystemApi @hide Allows an application to provide location-based time zone suggestions to
+ the system server. This is needed because the system server discovers time zone providers
+ by exposed intent actions and metadata, without it any app could potentially register
+ itself as time zone provider. The system server checks for this permission.
<p>Not for use by third-party applications.
-->
- <permission android:name="android.permission.INSTALL_LOCATION_TIME_ZONE_PROVIDER"
+ <permission android:name="android.permission.INSTALL_LOCATION_TIME_ZONE_PROVIDER_SERVICE"
android:protectionLevel="signature|privileged" />
+ <!-- The system server uses this permission to install a default secondary location time zone
+ provider.
+ -->
+ <uses-permission android:name="android.permission.INSTALL_LOCATION_TIME_ZONE_PROVIDER_SERVICE"/>
+
+ <!-- @SystemApi @hide Allows an application to bind to a android.service.TimeZoneProviderService
+ for the purpose of detecting the device's time zone. This prevents arbitrary clients
+ connecting to the time zone provider service. The system server checks that the provider's
+ intent service explicitly sets this permission via the android:permission attribute of the
+ service.
+ This is only expected to be possessed by the system server outside of tests.
+ <p>Not for use by third-party applications.
+ -->
+ <permission android:name="android.permission.BIND_TIME_ZONE_PROVIDER_SERVICE"
+ android:protectionLevel="signature" />
+
<!-- @SystemApi @hide Allows HDMI-CEC service to access device and configuration files.
This should only be used by HDMI-CEC service.
-->
@@ -5786,6 +5804,7 @@
data set from the com.android.geotz APEX. -->
<service android:name="com.android.timezone.geotz.provider.OfflineLocationTimeZoneProviderService"
android:enabled="@bool/config_enableSecondaryLocationTimeZoneProvider"
+ android:permission="android.permission.BIND_TIME_ZONE_PROVIDER_SERVICE"
android:exported="false">
<intent-filter>
<action android:name="android.service.timezone.SecondaryLocationTimeZoneProviderService" />
diff --git a/core/res/res/values/public.xml b/core/res/res/values/public.xml
index 4313d4a..0958434 100644
--- a/core/res/res/values/public.xml
+++ b/core/res/res/values/public.xml
@@ -3064,7 +3064,7 @@
<!-- dimension definitions go here -->
</public-group>
- <public-group type="bool" first-id="0x01110006">
+ <public-group type="bool" first-id="0x01110007">
<!-- boolean definitions go here -->
</public-group>
diff --git a/core/tests/batterystatstests/BatteryStatsViewer/src/com/android/frameworks/core/batterystatsviewer/BatteryConsumerData.java b/core/tests/batterystatstests/BatteryStatsViewer/src/com/android/frameworks/core/batterystatsviewer/BatteryConsumerData.java
index 8086ff2..e0d159b 100644
--- a/core/tests/batterystatstests/BatteryStatsViewer/src/com/android/frameworks/core/batterystatsviewer/BatteryConsumerData.java
+++ b/core/tests/batterystatstests/BatteryStatsViewer/src/com/android/frameworks/core/batterystatsviewer/BatteryConsumerData.java
@@ -171,6 +171,7 @@
mBatteryConsumerInfo = BatteryConsumerInfoHelper.makeBatteryConsumerInfo(
context.getPackageManager(), requestedBatterySipper);
long totalScreenMeasuredEnergyUJ = batteryStats.getScreenOnEnergy();
+ long uidScreenMeasuredEnergyUJ = requestedBatterySipper.uidObj.getScreenOnEnergy();
addEntry("Total power", EntryType.POWER,
requestedBatterySipper.totalSmearedPowerMah, totalSmearedPowerMah);
@@ -180,11 +181,12 @@
requestedBatterySipper.totalSmearedPowerMah, totalPowerExcludeSystemMah);
addEntry("Screen, smeared", EntryType.POWER,
requestedBatterySipper.screenPowerMah, totalScreenPower);
- if (totalScreenMeasuredEnergyUJ != BatteryStats.ENERGY_DATA_UNAVAILABLE) {
- final double measuredCharge = UJ_2_MAH * totalScreenMeasuredEnergyUJ;
- final double ratio = measuredCharge / totalScreenPower;
- addEntry("Screen, smeared (PowerStatsHal adjusted)", EntryType.POWER,
- requestedBatterySipper.screenPowerMah * ratio, measuredCharge);
+ if (uidScreenMeasuredEnergyUJ != BatteryStats.ENERGY_DATA_UNAVAILABLE
+ && totalScreenMeasuredEnergyUJ != BatteryStats.ENERGY_DATA_UNAVAILABLE) {
+ final double measuredCharge = UJ_2_MAH * uidScreenMeasuredEnergyUJ;
+ final double totalMeasuredCharge = UJ_2_MAH * totalScreenMeasuredEnergyUJ;
+ addEntry("Screen, measured", EntryType.POWER,
+ measuredCharge, totalMeasuredCharge);
}
addEntry("Other, smeared", EntryType.POWER,
requestedBatterySipper.proportionalSmearMah, totalProportionalSmearMah);
diff --git a/core/tests/coretests/src/android/app/appsearch/external/app/SearchSpecTest.java b/core/tests/coretests/src/android/app/appsearch/external/app/SearchSpecTest.java
index 9fd480d..b3caecc 100644
--- a/core/tests/coretests/src/android/app/appsearch/external/app/SearchSpecTest.java
+++ b/core/tests/coretests/src/android/app/appsearch/external/app/SearchSpecTest.java
@@ -22,6 +22,9 @@
import org.junit.Test;
+import java.util.List;
+import java.util.Map;
+
public class SearchSpecTest {
@Test
public void testGetBundle() {
@@ -53,4 +56,21 @@
assertThat(bundle.getInt(SearchSpec.RANKING_STRATEGY_FIELD))
.isEqualTo(SearchSpec.RANKING_STRATEGY_DOCUMENT_SCORE);
}
+
+ @Test
+ public void testGetProjectionTypePropertyMasks() {
+ SearchSpec searchSpec =
+ new SearchSpec.Builder()
+ .setTermMatch(SearchSpec.TERM_MATCH_PREFIX)
+ .addProjectionTypePropertyPaths("TypeA", "field1", "field2.subfield2")
+ .addProjectionTypePropertyPaths("TypeB", "field7")
+ .addProjectionTypePropertyPaths("TypeC")
+ .build();
+
+ Map<String, List<String>> typePropertyPathMap = searchSpec.getProjectionTypePropertyPaths();
+ assertThat(typePropertyPathMap.keySet()).containsExactly("TypeA", "TypeB", "TypeC");
+ assertThat(typePropertyPathMap.get("TypeA")).containsExactly("field1", "field2.subfield2");
+ assertThat(typePropertyPathMap.get("TypeB")).containsExactly("field7");
+ assertThat(typePropertyPathMap.get("TypeC")).isEmpty();
+ }
}
diff --git a/core/tests/coretests/src/android/app/assist/OWNERS b/core/tests/coretests/src/android/app/assist/OWNERS
new file mode 100644
index 0000000..43ad108
--- /dev/null
+++ b/core/tests/coretests/src/android/app/assist/OWNERS
@@ -0,0 +1 @@
+file:/core/java/android/app/assist/OWNERS
diff --git a/core/tests/coretests/src/android/app/servertransaction/ObjectPoolTests.java b/core/tests/coretests/src/android/app/servertransaction/ObjectPoolTests.java
index b2b34d6..50b52eb 100644
--- a/core/tests/coretests/src/android/app/servertransaction/ObjectPoolTests.java
+++ b/core/tests/coretests/src/android/app/servertransaction/ObjectPoolTests.java
@@ -23,9 +23,11 @@
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNotEquals;
import static org.junit.Assert.assertNotSame;
import static org.junit.Assert.assertSame;
+import android.app.ActivityOptions;
import android.app.servertransaction.TestUtils.LaunchActivityItemBuilder;
import android.content.Intent;
import android.content.pm.ActivityInfo;
@@ -247,6 +249,22 @@
}
@Test
+ public void testRecycleStartActivityItem() {
+ StartActivityItem emptyItem = StartActivityItem.obtain(null /* activityOptions */);
+ StartActivityItem item = StartActivityItem.obtain(ActivityOptions.makeBasic());
+ assertNotSame(item, emptyItem);
+ assertNotEquals(item, emptyItem);
+
+ item.recycle();
+ assertEquals(item, emptyItem);
+
+ StartActivityItem item2 = StartActivityItem.obtain(
+ ActivityOptions.makeBasic().setLaunchDisplayId(10));
+ assertSame(item, item2);
+ assertNotEquals(item2, emptyItem);
+ }
+
+ @Test
public void testRecycleStopItem() {
StopActivityItem emptyItem = StopActivityItem.obtain(0);
StopActivityItem item = StopActivityItem.obtain(4);
diff --git a/core/tests/coretests/src/android/app/servertransaction/TestUtils.java b/core/tests/coretests/src/android/app/servertransaction/TestUtils.java
index 7e9933c..02e75dd 100644
--- a/core/tests/coretests/src/android/app/servertransaction/TestUtils.java
+++ b/core/tests/coretests/src/android/app/servertransaction/TestUtils.java
@@ -18,6 +18,7 @@
import static android.content.res.Configuration.ORIENTATION_LANDSCAPE;
+import android.app.ActivityOptions;
import android.app.ProfilerInfo;
import android.app.ResultInfo;
import android.content.Intent;
@@ -104,6 +105,7 @@
private PersistableBundle mPersistentState;
private List<ResultInfo> mPendingResults;
private List<ReferrerIntent> mPendingNewIntents;
+ private ActivityOptions mActivityOptions;
private boolean mIsForward;
private ProfilerInfo mProfilerInfo;
private IBinder mAssistToken;
@@ -174,6 +176,11 @@
return this;
}
+ LaunchActivityItemBuilder setActivityOptions(ActivityOptions activityOptions) {
+ mActivityOptions = activityOptions;
+ return this;
+ }
+
LaunchActivityItemBuilder setIsForward(boolean isForward) {
mIsForward = isForward;
return this;
@@ -198,8 +205,8 @@
return LaunchActivityItem.obtain(mIntent, mIdent, mInfo,
mCurConfig, mOverrideConfig, mCompatInfo, mReferrer, mVoiceInteractor,
mProcState, mState, mPersistentState, mPendingResults, mPendingNewIntents,
- mIsForward, mProfilerInfo, mAssistToken, null /* activityClientController */,
- mFixedRotationAdjustments);
+ mActivityOptions, mIsForward, mProfilerInfo, mAssistToken,
+ null /* activityClientController */, mFixedRotationAdjustments);
}
}
}
diff --git a/core/tests/coretests/src/android/app/servertransaction/TransactionParcelTests.java b/core/tests/coretests/src/android/app/servertransaction/TransactionParcelTests.java
index e1c7146..5705dd5 100644
--- a/core/tests/coretests/src/android/app/servertransaction/TransactionParcelTests.java
+++ b/core/tests/coretests/src/android/app/servertransaction/TransactionParcelTests.java
@@ -24,6 +24,7 @@
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertTrue;
+import android.app.ActivityOptions;
import android.app.ContentProviderHolder;
import android.app.IApplicationThread;
import android.app.IInstrumentationWatcher;
@@ -200,9 +201,10 @@
.setIntent(intent).setIdent(ident).setInfo(activityInfo).setCurConfig(config())
.setOverrideConfig(overrideConfig).setCompatInfo(compat).setReferrer(referrer)
.setProcState(procState).setState(bundle).setPersistentState(persistableBundle)
- .setPendingResults(resultInfoList()).setPendingNewIntents(referrerIntentList())
- .setIsForward(true).setAssistToken(new Binder())
- .setFixedRotationAdjustments(fixedRotationAdjustments).build();
+ .setPendingResults(resultInfoList()).setActivityOptions(ActivityOptions.makeBasic())
+ .setPendingNewIntents(referrerIntentList()).setIsForward(true)
+ .setAssistToken(new Binder()).setFixedRotationAdjustments(fixedRotationAdjustments)
+ .build();
writeAndPrepareForReading(item);
@@ -273,7 +275,7 @@
@Test
public void testStart() {
// Write to parcel
- StartActivityItem item = StartActivityItem.obtain();
+ StartActivityItem item = StartActivityItem.obtain(ActivityOptions.makeBasic());
writeAndPrepareForReading(item);
// Read from parcel and assert
diff --git a/core/tests/coretests/src/android/service/notification/NotificationListenerFilterTest.java b/core/tests/coretests/src/android/service/notification/NotificationListenerFilterTest.java
new file mode 100644
index 0000000..a43b238
--- /dev/null
+++ b/core/tests/coretests/src/android/service/notification/NotificationListenerFilterTest.java
@@ -0,0 +1,124 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.service.notification;
+
+import static android.app.NotificationManager.IMPORTANCE_DEFAULT;
+import static android.service.notification.NotificationListenerService.FLAG_FILTER_TYPE_ALERTING;
+import static android.service.notification.NotificationListenerService.FLAG_FILTER_TYPE_CONVERSATIONS;
+import static android.service.notification.NotificationListenerService.FLAG_FILTER_TYPE_SILENT;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import android.app.NotificationChannel;
+import android.os.Parcel;
+import android.util.ArraySet;
+
+import androidx.test.filters.SmallTest;
+import androidx.test.runner.AndroidJUnit4;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+@RunWith(AndroidJUnit4.class)
+@SmallTest
+public class NotificationListenerFilterTest {
+
+ @Test
+ public void testEmptyConstructor() {
+ NotificationListenerFilter nlf = new NotificationListenerFilter();
+ assertThat(nlf.isTypeAllowed(FLAG_FILTER_TYPE_CONVERSATIONS)).isTrue();
+ assertThat(nlf.isTypeAllowed(FLAG_FILTER_TYPE_ALERTING)).isTrue();
+ assertThat(nlf.isTypeAllowed(FLAG_FILTER_TYPE_SILENT)).isTrue();
+ assertThat(nlf.getTypes()).isEqualTo(FLAG_FILTER_TYPE_CONVERSATIONS
+ | FLAG_FILTER_TYPE_ALERTING
+ | FLAG_FILTER_TYPE_SILENT);
+
+ assertThat(nlf.getDisallowedPackages()).isEmpty();
+ assertThat(nlf.isPackageAllowed("pkg1")).isTrue();
+ }
+
+
+ @Test
+ public void testConstructor() {
+ ArraySet<String> pkgs = new ArraySet<>(new String[] {"pkg1", "pkg2"});
+ NotificationListenerFilter nlf =
+ new NotificationListenerFilter(FLAG_FILTER_TYPE_ALERTING, pkgs);
+ assertThat(nlf.isTypeAllowed(FLAG_FILTER_TYPE_CONVERSATIONS)).isFalse();
+ assertThat(nlf.isTypeAllowed(FLAG_FILTER_TYPE_ALERTING)).isTrue();
+ assertThat(nlf.isTypeAllowed(FLAG_FILTER_TYPE_SILENT)).isFalse();
+ assertThat(nlf.getTypes()).isEqualTo(FLAG_FILTER_TYPE_ALERTING);
+
+ assertThat(nlf.getDisallowedPackages()).contains("pkg1");
+ assertThat(nlf.getDisallowedPackages()).contains("pkg2");
+ assertThat(nlf.isPackageAllowed("pkg1")).isFalse();
+ assertThat(nlf.isPackageAllowed("pkg2")).isFalse();
+ }
+
+ @Test
+ public void testSetDisallowedPackages() {
+ NotificationListenerFilter nlf = new NotificationListenerFilter();
+
+ ArraySet<String> pkgs = new ArraySet<>(new String[] {"pkg1"});
+ nlf.setDisallowedPackages(pkgs);
+
+ assertThat(nlf.isPackageAllowed("pkg1")).isFalse();
+ }
+
+ @Test
+ public void testSetTypes() {
+ NotificationListenerFilter nlf = new NotificationListenerFilter();
+
+ nlf.setTypes(FLAG_FILTER_TYPE_ALERTING | FLAG_FILTER_TYPE_SILENT);
+
+ assertThat(nlf.isTypeAllowed(FLAG_FILTER_TYPE_CONVERSATIONS)).isFalse();
+ assertThat(nlf.isTypeAllowed(FLAG_FILTER_TYPE_ALERTING)).isTrue();
+ assertThat(nlf.isTypeAllowed(FLAG_FILTER_TYPE_SILENT)).isTrue();
+ assertThat(nlf.getTypes()).isEqualTo(FLAG_FILTER_TYPE_ALERTING
+ | FLAG_FILTER_TYPE_SILENT);
+ }
+
+ @Test
+ public void testDescribeContents() {
+ final int expected = 0;
+ ArraySet<String> pkgs = new ArraySet<>(new String[] {"pkg1", "pkg2"});
+ NotificationListenerFilter nlf =
+ new NotificationListenerFilter(FLAG_FILTER_TYPE_ALERTING, pkgs);
+ assertThat(nlf.describeContents()).isEqualTo(expected);
+ }
+
+ @Test
+ public void testParceling() {
+ ArraySet<String> pkgs = new ArraySet<>(new String[] {"pkg1", "pkg2"});
+ NotificationListenerFilter nlf =
+ new NotificationListenerFilter(FLAG_FILTER_TYPE_ALERTING, pkgs);
+
+ Parcel parcel = Parcel.obtain();
+ nlf.writeToParcel(parcel, 0);
+ parcel.setDataPosition(0);
+ NotificationListenerFilter nlf1 =
+ NotificationListenerFilter.CREATOR.createFromParcel(parcel);
+ assertThat(nlf1.isTypeAllowed(FLAG_FILTER_TYPE_CONVERSATIONS)).isFalse();
+ assertThat(nlf1.isTypeAllowed(FLAG_FILTER_TYPE_ALERTING)).isTrue();
+ assertThat(nlf1.isTypeAllowed(FLAG_FILTER_TYPE_SILENT)).isFalse();
+ assertThat(nlf1.getTypes()).isEqualTo(FLAG_FILTER_TYPE_ALERTING);
+
+ assertThat(nlf1.getDisallowedPackages()).contains("pkg1");
+ assertThat(nlf1.getDisallowedPackages()).contains("pkg2");
+ assertThat(nlf1.isPackageAllowed("pkg1")).isFalse();
+ assertThat(nlf1.isPackageAllowed("pkg2")).isFalse();
+ }
+}
diff --git a/core/tests/coretests/src/android/view/ImeInsetsSourceConsumerTest.java b/core/tests/coretests/src/android/view/ImeInsetsSourceConsumerTest.java
index 970ab79..7a2e6b7 100644
--- a/core/tests/coretests/src/android/view/ImeInsetsSourceConsumerTest.java
+++ b/core/tests/coretests/src/android/view/ImeInsetsSourceConsumerTest.java
@@ -78,11 +78,11 @@
mController = Mockito.spy(new InsetsController(
new ViewRootInsetsControllerHost(viewRootImpl)));
final Rect rect = new Rect(5, 5, 5, 5);
+ mController.getState().setDisplayCutout(new DisplayCutout(
+ Insets.of(10, 10, 10, 10), rect, rect, rect, rect));
mController.calculateInsets(
false,
false,
- new DisplayCutout(
- Insets.of(10, 10, 10, 10), rect, rect, rect, rect),
TYPE_APPLICATION, WINDOWING_MODE_UNDEFINED,
SOFT_INPUT_ADJUST_RESIZE, 0, 0);
mImeConsumer = (ImeInsetsSourceConsumer) mController.getSourceConsumer(ITYPE_IME);
diff --git a/core/tests/coretests/src/android/view/InsetsControllerTest.java b/core/tests/coretests/src/android/view/InsetsControllerTest.java
index 7b84f68c..af13cc0 100644
--- a/core/tests/coretests/src/android/view/InsetsControllerTest.java
+++ b/core/tests/coretests/src/android/view/InsetsControllerTest.java
@@ -151,11 +151,11 @@
new Rect(0, 90, 100, 100));
mController.getState().getSource(ITYPE_IME).setFrame(new Rect(0, 50, 100, 100));
mController.getState().setDisplayFrame(new Rect(0, 0, 100, 100));
+ mController.getState().setDisplayCutout(new DisplayCutout(
+ Insets.of(10, 10, 10, 10), rect, rect, rect, rect));
mController.calculateInsets(
false,
false,
- new DisplayCutout(
- Insets.of(10, 10, 10, 10), rect, rect, rect, rect),
TYPE_APPLICATION, WINDOWING_MODE_UNDEFINED,
SOFT_INPUT_ADJUST_RESIZE, 0, 0);
mController.onFrameChanged(new Rect(0, 0, 100, 100));
diff --git a/core/tests/coretests/src/android/view/InsetsStateTest.java b/core/tests/coretests/src/android/view/InsetsStateTest.java
index 8a000a0..9705284 100644
--- a/core/tests/coretests/src/android/view/InsetsStateTest.java
+++ b/core/tests/coretests/src/android/view/InsetsStateTest.java
@@ -37,6 +37,7 @@
import static android.view.WindowManager.LayoutParams.SOFT_INPUT_ADJUST_NOTHING;
import static android.view.WindowManager.LayoutParams.SOFT_INPUT_ADJUST_PAN;
import static android.view.WindowManager.LayoutParams.SOFT_INPUT_ADJUST_RESIZE;
+import static android.view.WindowManager.LayoutParams.SOFT_INPUT_ADJUST_UNSPECIFIED;
import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION;
import static android.view.WindowManager.LayoutParams.TYPE_SYSTEM_ERROR;
import static android.view.WindowManager.LayoutParams.TYPE_WALLPAPER;
@@ -82,8 +83,8 @@
mState.getSource(ITYPE_IME).setVisible(true);
SparseIntArray typeSideMap = new SparseIntArray();
WindowInsets insets = mState.calculateInsets(new Rect(0, 0, 100, 300), null, false,
- false, DisplayCutout.NO_CUTOUT, SOFT_INPUT_ADJUST_RESIZE, 0, 0,
- TYPE_APPLICATION, WINDOWING_MODE_UNDEFINED, typeSideMap);
+ false, SOFT_INPUT_ADJUST_RESIZE, 0, 0, TYPE_APPLICATION, WINDOWING_MODE_UNDEFINED,
+ typeSideMap);
assertEquals(Insets.of(0, 100, 0, 100), insets.getSystemWindowInsets());
assertEquals(Insets.of(0, 100, 0, 100), insets.getInsets(Type.all()));
assertEquals(ISIDE_TOP, typeSideMap.get(ITYPE_STATUS_BAR));
@@ -99,8 +100,8 @@
mState.getSource(ITYPE_IME).setFrame(new Rect(0, 100, 100, 300));
mState.getSource(ITYPE_IME).setVisible(true);
WindowInsets insets = mState.calculateInsets(new Rect(0, 0, 100, 300), null, false,
- false, DisplayCutout.NO_CUTOUT, SOFT_INPUT_ADJUST_RESIZE, 0, 0,
- TYPE_APPLICATION, WINDOWING_MODE_UNDEFINED, null);
+ false, SOFT_INPUT_ADJUST_RESIZE, 0, 0, TYPE_APPLICATION, WINDOWING_MODE_UNDEFINED,
+ null);
assertEquals(100, insets.getStableInsetBottom());
assertEquals(Insets.of(0, 0, 0, 100), insets.getInsetsIgnoringVisibility(systemBars()));
assertEquals(Insets.of(0, 0, 0, 200), insets.getSystemWindowInsets());
@@ -116,8 +117,7 @@
mState.getSource(ITYPE_NAVIGATION_BAR).setFrame(new Rect(80, 0, 100, 300));
mState.getSource(ITYPE_NAVIGATION_BAR).setVisible(true);
WindowInsets insets = mState.calculateInsets(new Rect(0, 0, 100, 300), null, false,
- false, DisplayCutout.NO_CUTOUT, 0, 0, 0, TYPE_APPLICATION,
- WINDOWING_MODE_UNDEFINED, null);
+ false, 0, 0, 0, TYPE_APPLICATION, WINDOWING_MODE_UNDEFINED, null);
assertEquals(Insets.of(0, 100, 20, 0), insets.getSystemWindowInsets());
assertEquals(Insets.of(0, 100, 0, 0), insets.getInsets(statusBars()));
assertEquals(Insets.of(0, 0, 20, 0), insets.getInsets(navigationBars()));
@@ -130,8 +130,7 @@
mState.getSource(ITYPE_EXTRA_NAVIGATION_BAR).setFrame(new Rect(80, 0, 100, 300));
mState.getSource(ITYPE_EXTRA_NAVIGATION_BAR).setVisible(true);
WindowInsets insets = mState.calculateInsets(new Rect(0, 0, 100, 300), null, false,
- false, DisplayCutout.NO_CUTOUT, 0, 0, 0, TYPE_APPLICATION,
- WINDOWING_MODE_UNDEFINED, null);
+ false, 0, 0, 0, TYPE_APPLICATION, WINDOWING_MODE_UNDEFINED, null);
// ITYPE_CLIMATE_BAR is a type of status bar and ITYPE_EXTRA_NAVIGATION_BAR is a type
// of navigation bar.
assertEquals(Insets.of(0, 100, 20, 0), insets.getSystemWindowInsets());
@@ -146,8 +145,8 @@
mState.getSource(ITYPE_IME).setFrame(new Rect(0, 200, 100, 300));
mState.getSource(ITYPE_IME).setVisible(true);
WindowInsets insets = mState.calculateInsets(new Rect(0, 0, 100, 300), null, false,
- false, DisplayCutout.NO_CUTOUT, SOFT_INPUT_ADJUST_NOTHING, 0, 0,
- TYPE_APPLICATION, WINDOWING_MODE_UNDEFINED, null);
+ false, SOFT_INPUT_ADJUST_NOTHING, 0, 0, TYPE_APPLICATION, WINDOWING_MODE_UNDEFINED,
+ null);
assertEquals(0, insets.getSystemWindowInsetBottom());
assertEquals(100, insets.getInsets(ime()).bottom);
assertTrue(insets.isVisible(ime()));
@@ -160,12 +159,12 @@
mState.getSource(ITYPE_IME).setFrame(new Rect(0, 200, 100, 300));
mState.getSource(ITYPE_IME).setVisible(true);
WindowInsets insets = mState.calculateInsets(new Rect(0, 0, 100, 300), null, false,
- false, DisplayCutout.NO_CUTOUT, SOFT_INPUT_ADJUST_NOTHING, 0,
- SYSTEM_UI_FLAG_LAYOUT_STABLE, TYPE_APPLICATION, WINDOWING_MODE_UNDEFINED, null);
+ false, SOFT_INPUT_ADJUST_NOTHING, 0, SYSTEM_UI_FLAG_LAYOUT_STABLE, TYPE_APPLICATION,
+ WINDOWING_MODE_UNDEFINED, null);
assertEquals(100, insets.getSystemWindowInsetTop());
insets = mState.calculateInsets(new Rect(0, 0, 100, 300), null, false, false,
- DisplayCutout.NO_CUTOUT, SOFT_INPUT_ADJUST_NOTHING, 0,
- 0 /* legacySystemUiFlags */, TYPE_APPLICATION, WINDOWING_MODE_UNDEFINED, null);
+ SOFT_INPUT_ADJUST_NOTHING, 0, 0 /* legacySystemUiFlags */, TYPE_APPLICATION,
+ WINDOWING_MODE_UNDEFINED, null);
assertEquals(0, insets.getSystemWindowInsetTop());
}
@@ -174,12 +173,12 @@
mState.getSource(ITYPE_STATUS_BAR).setFrame(new Rect(0, 0, 100, 100));
mState.getSource(ITYPE_STATUS_BAR).setVisible(false);
WindowInsets insets = mState.calculateInsets(new Rect(0, 0, 100, 300), null, false,
- false, DisplayCutout.NO_CUTOUT, SOFT_INPUT_ADJUST_NOTHING, FLAG_FULLSCREEN,
- SYSTEM_UI_FLAG_LAYOUT_STABLE, TYPE_APPLICATION, WINDOWING_MODE_UNDEFINED, null);
+ false, SOFT_INPUT_ADJUST_NOTHING, FLAG_FULLSCREEN, SYSTEM_UI_FLAG_LAYOUT_STABLE,
+ TYPE_APPLICATION, WINDOWING_MODE_UNDEFINED, null);
assertEquals(0, insets.getSystemWindowInsetTop());
insets = mState.calculateInsets(new Rect(0, 0, 100, 300), null, false, false,
- DisplayCutout.NO_CUTOUT, SOFT_INPUT_ADJUST_NOTHING, 0,
- 0 /* legacySystemUiFlags */, TYPE_APPLICATION, WINDOWING_MODE_UNDEFINED, null);
+ SOFT_INPUT_ADJUST_NOTHING, 0, 0 /* legacySystemUiFlags */, TYPE_APPLICATION,
+ WINDOWING_MODE_UNDEFINED, null);
assertEquals(0, insets.getSystemWindowInsetTop());
}
@@ -188,19 +187,19 @@
mState.getSource(ITYPE_STATUS_BAR).setFrame(new Rect(0, 0, 100, 100));
mState.getSource(ITYPE_STATUS_BAR).setVisible(true);
WindowInsets insets = mState.calculateInsets(new Rect(0, 0, 100, 300), null, false,
- false, DisplayCutout.NO_CUTOUT, SOFT_INPUT_ADJUST_NOTHING, FLAG_LAYOUT_NO_LIMITS,
+ false, SOFT_INPUT_ADJUST_NOTHING, FLAG_LAYOUT_NO_LIMITS,
0 /* legacySystemUiFlags */, TYPE_APPLICATION, WINDOWING_MODE_UNDEFINED, null);
assertEquals(0, insets.getSystemWindowInsetTop());
insets = mState.calculateInsets(new Rect(0, 0, 100, 300), null, false,
- false, DisplayCutout.NO_CUTOUT, SOFT_INPUT_ADJUST_NOTHING, FLAG_LAYOUT_NO_LIMITS,
+ false, SOFT_INPUT_ADJUST_NOTHING, FLAG_LAYOUT_NO_LIMITS,
0 /* legacySystemUiFlags */, TYPE_SYSTEM_ERROR, WINDOWING_MODE_UNDEFINED, null);
assertEquals(100, insets.getSystemWindowInsetTop());
insets = mState.calculateInsets(new Rect(0, 0, 100, 300), null, false,
- false, DisplayCutout.NO_CUTOUT, SOFT_INPUT_ADJUST_NOTHING, FLAG_LAYOUT_NO_LIMITS,
+ false, SOFT_INPUT_ADJUST_NOTHING, FLAG_LAYOUT_NO_LIMITS,
0 /* legacySystemUiFlags */, TYPE_WALLPAPER, WINDOWING_MODE_UNDEFINED, null);
assertEquals(100, insets.getSystemWindowInsetTop());
insets = mState.calculateInsets(new Rect(0, 0, 100, 300), null, false,
- false, DisplayCutout.NO_CUTOUT, SOFT_INPUT_ADJUST_NOTHING, FLAG_LAYOUT_NO_LIMITS,
+ false, SOFT_INPUT_ADJUST_NOTHING, FLAG_LAYOUT_NO_LIMITS,
0 /* legacySystemUiFlags */, TYPE_APPLICATION, WINDOWING_MODE_FREEFORM, null);
assertEquals(100, insets.getSystemWindowInsetTop());
}
@@ -235,8 +234,7 @@
mState.getSource(ITYPE_EXTRA_NAVIGATION_BAR).setFrame(new Rect(80, 0, 100, 300));
mState.getSource(ITYPE_EXTRA_NAVIGATION_BAR).setVisible(true);
WindowInsets insets = mState.calculateInsets(new Rect(0, 0, 100, 300), null, false,
- false, DisplayCutout.NO_CUTOUT, 0, 0, 0, TYPE_APPLICATION,
- WINDOWING_MODE_UNDEFINED, null);
+ false, 0, 0, 0, TYPE_APPLICATION, WINDOWING_MODE_UNDEFINED, null);
assertEquals(Insets.of(0, 100, 20, 0), insets.getSystemWindowInsets());
assertEquals(Insets.of(0, 100, 0, 0), insets.getInsets(statusBars()));
assertEquals(Insets.of(0, 0, 20, 0), insets.getInsets(navigationBars()));
@@ -249,8 +247,7 @@
mState.getSource(ITYPE_NAVIGATION_BAR).setFrame(new Rect(80, 0, 100, 300));
mState.getSource(ITYPE_NAVIGATION_BAR).setVisible(true);
WindowInsets insets = mState.calculateInsets(new Rect(0, 0, 100, 300), null, false,
- false, DisplayCutout.NO_CUTOUT, 0, 0, 0, TYPE_APPLICATION,
- WINDOWING_MODE_UNDEFINED, null);
+ false, 0, 0, 0, TYPE_APPLICATION, WINDOWING_MODE_UNDEFINED, null);
assertEquals(Insets.of(0, 100, 20, 0), insets.getSystemWindowInsets());
assertEquals(Insets.of(0, 100, 0, 0), insets.getInsets(statusBars()));
assertEquals(Insets.of(0, 0, 20, 0), insets.getInsets(navigationBars()));
@@ -264,8 +261,7 @@
mState.getSource(ITYPE_IME).setVisible(true);
mState.removeSource(ITYPE_IME);
WindowInsets insets = mState.calculateInsets(new Rect(0, 0, 100, 300), null, false, false,
- DisplayCutout.NO_CUTOUT, SOFT_INPUT_ADJUST_RESIZE, 0, 0, TYPE_APPLICATION,
- WINDOWING_MODE_UNDEFINED, null);
+ SOFT_INPUT_ADJUST_RESIZE, 0, 0, TYPE_APPLICATION, WINDOWING_MODE_UNDEFINED, null);
assertEquals(0, insets.getSystemWindowInsetBottom());
}
@@ -406,6 +402,31 @@
mState.calculateUncontrollableInsetsFromFrame(new Rect(50, 0, 150, 300)));
}
+ @Test
+ public void testCalculateRelativeCutout() {
+ mState.setDisplayFrame(new Rect(0, 0, 200, 300));
+ mState.setDisplayCutout(new DisplayCutout(Insets.of(1, 2, 3, 4),
+ new Rect(0, 0, 1, 2),
+ new Rect(0, 0, 1, 2),
+ new Rect(197, 296, 200, 300),
+ new Rect(197, 296, 200, 300)));
+ DisplayCutout cutout = mState.calculateInsets(new Rect(1, 1, 199, 300), null, false, false,
+ SOFT_INPUT_ADJUST_UNSPECIFIED, 0, 0, TYPE_APPLICATION, WINDOWING_MODE_UNDEFINED,
+ new SparseIntArray()).getDisplayCutout();
+ assertEquals(0, cutout.getSafeInsetLeft());
+ assertEquals(1, cutout.getSafeInsetTop());
+ assertEquals(2, cutout.getSafeInsetRight());
+ assertEquals(4, cutout.getSafeInsetBottom());
+ assertEquals(new Rect(-1, -1, 0, 1),
+ cutout.getBoundingRectLeft());
+ assertEquals(new Rect(-1, -1, 0, 1),
+ cutout.getBoundingRectTop());
+ assertEquals(new Rect(196, 295, 199, 299),
+ cutout.getBoundingRectRight());
+ assertEquals(new Rect(196, 295, 199, 299),
+ cutout.getBoundingRectBottom());
+ }
+
private void assertEqualsAndHashCode() {
assertEquals(mState, mState2);
assertEquals(mState.hashCode(), mState2.hashCode());
diff --git a/core/tests/coretests/src/android/view/OWNERS b/core/tests/coretests/src/android/view/OWNERS
index a3a3e7c..5031ff9 100644
--- a/core/tests/coretests/src/android/view/OWNERS
+++ b/core/tests/coretests/src/android/view/OWNERS
@@ -2,3 +2,10 @@
per-file *MotionEventTest.* = michaelwr@google.com, svv@google.com
per-file *KeyEventTest.* = michaelwr@google.com, svv@google.com
per-file VelocityTest.java = michaelwr@google.com, svv@google.com
+
+# WindowManager
+per-file *Display* = file:/services/core/java/com/android/server/wm/OWNERS
+per-file *Focus* = file:/services/core/java/com/android/server/wm/OWNERS
+per-file *Insets* = file:/services/core/java/com/android/server/wm/OWNERS
+per-file *View* = file:/services/core/java/com/android/server/wm/OWNERS
+per-file *Visibility* = file:/services/core/java/com/android/server/wm/OWNERS
diff --git a/core/tests/coretests/src/android/view/ViewRootImplTest.java b/core/tests/coretests/src/android/view/ViewRootImplTest.java
index 4cf6715..830771c 100644
--- a/core/tests/coretests/src/android/view/ViewRootImplTest.java
+++ b/core/tests/coretests/src/android/view/ViewRootImplTest.java
@@ -22,7 +22,8 @@
import static android.view.View.SYSTEM_UI_FLAG_LIGHT_NAVIGATION_BAR;
import static android.view.View.SYSTEM_UI_FLAG_LIGHT_STATUS_BAR;
import static android.view.View.SYSTEM_UI_FLAG_LOW_PROFILE;
-import static android.view.WindowInsetsController.BEHAVIOR_SHOW_BARS_BY_TOUCH;
+import static android.view.WindowInsetsController.APPEARANCE_OPAQUE_STATUS_BARS;
+import static android.view.WindowInsetsController.BEHAVIOR_SHOW_BARS_BY_SWIPE;
import static android.view.WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN;
import static android.view.WindowManager.LayoutParams.SOFT_INPUT_ADJUST_RESIZE;
import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION;
@@ -153,7 +154,7 @@
public void adjustLayoutParamsForCompatibility_noAdjustAppearance() {
final WindowInsetsController controller = mViewRootImpl.getInsetsController();
final WindowManager.LayoutParams attrs = mViewRootImpl.mWindowAttributes;
- final int appearance = 0;
+ final int appearance = APPEARANCE_OPAQUE_STATUS_BARS;
controller.setSystemBarsAppearance(appearance, 0xffffffff);
attrs.systemUiVisibility = SYSTEM_UI_FLAG_LOW_PROFILE
| SYSTEM_UI_FLAG_LIGHT_STATUS_BAR
@@ -163,13 +164,18 @@
// Appearance must not be adjusted due to legacy system UI visibility after calling
// setSystemBarsAppearance.
assertEquals(appearance, controller.getSystemBarsAppearance());
+
+ mViewRootImpl.setLayoutParams(new WindowManager.LayoutParams(), false);
+
+ // Appearance must not be adjusted due to setting new LayoutParams.
+ assertEquals(appearance, controller.getSystemBarsAppearance());
}
@Test
public void adjustLayoutParamsForCompatibility_noAdjustBehavior() {
final WindowInsetsController controller = mViewRootImpl.getInsetsController();
final WindowManager.LayoutParams attrs = mViewRootImpl.mWindowAttributes;
- final int behavior = BEHAVIOR_SHOW_BARS_BY_TOUCH;
+ final int behavior = BEHAVIOR_SHOW_BARS_BY_SWIPE;
controller.setSystemBarsBehavior(behavior);
attrs.systemUiVisibility = SYSTEM_UI_FLAG_IMMERSIVE_STICKY;
ViewRootImpl.adjustLayoutParamsForCompatibility(attrs);
@@ -177,5 +183,10 @@
// Behavior must not be adjusted due to legacy system UI visibility after calling
// setSystemBarsBehavior.
assertEquals(behavior, controller.getSystemBarsBehavior());
+
+ mViewRootImpl.setLayoutParams(new WindowManager.LayoutParams(), false);
+
+ // Behavior must not be adjusted due to setting new LayoutParams.
+ assertEquals(behavior, controller.getSystemBarsBehavior());
}
}
diff --git a/core/tests/mockingcoretests/src/android/app/activity/ActivityThreadClientTest.java b/core/tests/mockingcoretests/src/android/app/activity/ActivityThreadClientTest.java
index a74f580..d2b20b4 100644
--- a/core/tests/mockingcoretests/src/android/app/activity/ActivityThreadClientTest.java
+++ b/core/tests/mockingcoretests/src/android/app/activity/ActivityThreadClientTest.java
@@ -242,7 +242,7 @@
}
private void startActivity(ActivityClientRecord r) {
- mThread.handleStartActivity(r, null /* pendingActions */);
+ mThread.handleStartActivity(r, null /* pendingActions */, null /* activityOptions */);
}
private void resumeActivity(ActivityClientRecord r) {
@@ -295,8 +295,9 @@
0 /* ident */, info, new Configuration(),
CompatibilityInfo.DEFAULT_COMPATIBILITY_INFO, null /* referrer */,
null /* voiceInteractor */, null /* state */, null /* persistentState */,
- null /* pendingResults */, null /* pendingNewIntents */, true /* isForward */,
- null /* profilerInfo */, mThread /* client */, null /* asssitToken */,
+ null /* pendingResults */, null /* pendingNewIntents */,
+ null /* activityOptions */, true /* isForward */, null /* profilerInfo */,
+ mThread /* client */, null /* asssitToken */,
null /* fixedRotationAdjustments */);
}
diff --git a/data/etc/privapp-permissions-platform.xml b/data/etc/privapp-permissions-platform.xml
index 2e12795..91e6455 100644
--- a/data/etc/privapp-permissions-platform.xml
+++ b/data/etc/privapp-permissions-platform.xml
@@ -350,6 +350,8 @@
<permission name="android.permission.MOUNT_FORMAT_FILESYSTEMS"/>
<permission name="android.permission.MOUNT_UNMOUNT_FILESYSTEMS"/>
<permission name="android.permission.MOVE_PACKAGE"/>
+ <!-- Needed for test only -->
+ <permission name="android.permission.NETWORK_AIRPLANE_MODE"/>
<permission name="android.permission.OBSERVE_APP_USAGE"/>
<permission name="android.permission.NETWORK_SCAN"/>
<permission name="android.permission.PACKAGE_USAGE_STATS" />
diff --git a/data/keyboards/Vendor_0957_Product_0001.idc b/data/keyboards/Vendor_0957_Product_0001.idc
new file mode 100644
index 0000000..e1f4346
--- /dev/null
+++ b/data/keyboards/Vendor_0957_Product_0001.idc
@@ -0,0 +1,23 @@
+# Copyright (C) 2021 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.
+
+#
+# Input Device Configuration file for Google Reference RCU Remote.
+#
+#
+
+# Basic Parameters
+keyboard.layout = Vendor_0957_Product_0001
+keyboard.characterMap = Vendor_0957_Product_0001
+audio.mic = 1
\ No newline at end of file
diff --git a/data/keyboards/Vendor_0957_Product_0001.kl b/data/keyboards/Vendor_0957_Product_0001.kl
new file mode 100644
index 0000000..e9f4f28
--- /dev/null
+++ b/data/keyboards/Vendor_0957_Product_0001.kl
@@ -0,0 +1,72 @@
+# Copyright (C) 2021 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.
+
+#
+# Key Layout file for Google Reference RCU Remote.
+#
+
+key 116 POWER WAKE
+key 217 ASSIST WAKE
+
+key 103 DPAD_UP
+key 108 DPAD_DOWN
+key 105 DPAD_LEFT
+key 106 DPAD_RIGHT
+key 353 DPAD_CENTER
+
+key 158 BACK
+key 172 HOME WAKE
+
+key 113 VOLUME_MUTE
+key 114 VOLUME_DOWN
+key 115 VOLUME_UP
+
+key 2 1
+key 3 2
+key 4 3
+key 5 4
+key 6 5
+key 7 6
+key 8 7
+key 9 8
+key 10 9
+key 11 0
+
+# custom keys
+key usage 0x000c01BB TV_INPUT
+key usage 0x000c022A BOOKMARK
+key usage 0x000c0096 SETTINGS
+key usage 0x000c0097 NOTIFICATION
+key usage 0x000c008D GUIDE
+key usage 0x000c0089 TV
+key usage 0x000c009C CHANNEL_UP
+key usage 0x000c009D CHANNEL_DOWN
+key usage 0x000c00CD MEDIA_PLAY_PAUSE
+key usage 0x000c00B4 MEDIA_SKIP_BACKWARD
+key usage 0x000c00B3 MEDIA_SKIP_FORWARD
+key usage 0x000c0226 MEDIA_STOP
+
+key usage 0x000c0077 BUTTON_3 WAKE #YouTube
+key usage 0x000c0078 BUTTON_4 WAKE #Netflix
+key usage 0x000c0079 BUTTON_6 WAKE #Disney+
+key usage 0x000c007A BUTTON_7 WAKE #HBOmax
+
+key usage 0x000c01BD INFO
+key usage 0x000c0061 CAPTIONS
+key usage 0x000c0185 TV_TELETEXT
+
+key usage 0x000c0069 PROG_RED
+key usage 0x000c006A PROG_GREEN
+key usage 0x000c006B PROG_BLUE
+key usage 0x000c006C PROG_YELLOW
\ No newline at end of file
diff --git a/graphics/OWNERS b/graphics/OWNERS
index a6d1bc3..5851cbb 100644
--- a/graphics/OWNERS
+++ b/graphics/OWNERS
@@ -1 +1 @@
-include /core/java/android/graphics/OWNERS
+include /graphics/java/android/graphics/OWNERS
\ No newline at end of file
diff --git a/graphics/java/android/graphics/drawable/Icon.java b/graphics/java/android/graphics/drawable/Icon.java
index dcd4f33..8da8056 100644
--- a/graphics/java/android/graphics/drawable/Icon.java
+++ b/graphics/java/android/graphics/drawable/Icon.java
@@ -21,7 +21,6 @@
import android.annotation.ColorInt;
import android.annotation.DrawableRes;
-import android.annotation.IdRes;
import android.annotation.IntDef;
import android.annotation.NonNull;
import android.compat.annotation.UnsupportedAppUsage;
@@ -248,7 +247,7 @@
* Note: This resource may not be available if the application changes at all, and it is
* up to the caller to ensure safety if this resource is re-used and/or persisted.
*/
- @IdRes
+ @DrawableRes
public int getResId() {
if (mType != TYPE_RESOURCE) {
throw new IllegalStateException("called getResId() on " + this);
diff --git a/keystore/java/android/security/AndroidProtectedConfirmation.java b/keystore/java/android/security/AndroidProtectedConfirmation.java
new file mode 100644
index 0000000..dfe485a
--- /dev/null
+++ b/keystore/java/android/security/AndroidProtectedConfirmation.java
@@ -0,0 +1,118 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.security;
+
+import android.os.RemoteException;
+import android.os.ServiceManager;
+import android.os.ServiceSpecificException;
+import android.security.apc.IConfirmationCallback;
+import android.security.apc.IProtectedConfirmation;
+import android.security.apc.ResponseCode;
+import android.util.Log;
+
+/**
+ * @hide
+ */
+public class AndroidProtectedConfirmation {
+ private static final String TAG = "AndroidProtectedConfirmation";
+
+ public static final int ERROR_OK = ResponseCode.OK;
+ public static final int ERROR_CANCELED = ResponseCode.CANCELLED;
+ public static final int ERROR_ABORTED = ResponseCode.ABORTED;
+ public static final int ERROR_OPERATION_PENDING = ResponseCode.OPERATION_PENDING;
+ public static final int ERROR_IGNORED = ResponseCode.IGNORED;
+ public static final int ERROR_SYSTEM_ERROR = ResponseCode.SYSTEM_ERROR;
+ public static final int ERROR_UNIMPLEMENTED = ResponseCode.UNIMPLEMENTED;
+
+ public static final int FLAG_UI_OPTION_INVERTED =
+ IProtectedConfirmation.FLAG_UI_OPTION_INVERTED;
+ public static final int FLAG_UI_OPTION_MAGNIFIED =
+ IProtectedConfirmation.FLAG_UI_OPTION_MAGNIFIED;
+
+ private IProtectedConfirmation mProtectedConfirmation;
+
+ public AndroidProtectedConfirmation() {
+ mProtectedConfirmation = null;
+ }
+
+ private synchronized IProtectedConfirmation getService() {
+ if (mProtectedConfirmation == null) {
+ mProtectedConfirmation = IProtectedConfirmation.Stub.asInterface(ServiceManager
+ .getService("android.security.apc"));
+ }
+ return mProtectedConfirmation;
+ }
+
+ /**
+ * Requests keystore call into the confirmationui HAL to display a prompt.
+ *
+ * @param listener the binder to use for callbacks.
+ * @param promptText the prompt to display.
+ * @param extraData extra data / nonce from application.
+ * @param locale the locale as a BCP 47 language tag.
+ * @param uiOptionsAsFlags the UI options to use, as flags.
+ * @return one of the {@code CONFIRMATIONUI_*} constants, for
+ * example {@code KeyStore.CONFIRMATIONUI_OK}.
+ */
+ public int presentConfirmationPrompt(IConfirmationCallback listener, String promptText,
+ byte[] extraData, String locale, int uiOptionsAsFlags) {
+ try {
+ getService().presentPrompt(listener, promptText, extraData, locale,
+ uiOptionsAsFlags);
+ return ERROR_OK;
+ } catch (RemoteException e) {
+ Log.w(TAG, "Cannot connect to keystore", e);
+ return ERROR_SYSTEM_ERROR;
+ } catch (ServiceSpecificException e) {
+ return e.errorCode;
+ }
+ }
+
+ /**
+ * Requests keystore call into the confirmationui HAL to cancel displaying a prompt.
+ *
+ * @param listener the binder passed to the {@link #presentConfirmationPrompt} method.
+ * @return one of the {@code CONFIRMATIONUI_*} constants, for
+ * example {@code KeyStore.CONFIRMATIONUI_OK}.
+ */
+ public int cancelConfirmationPrompt(IConfirmationCallback listener) {
+ try {
+ getService().cancelPrompt(listener);
+ return ERROR_OK;
+ } catch (RemoteException e) {
+ Log.w(TAG, "Cannot connect to keystore", e);
+ return ERROR_SYSTEM_ERROR;
+ } catch (ServiceSpecificException e) {
+ return e.errorCode;
+ }
+ }
+
+ /**
+ * Requests keystore to check if the confirmationui HAL is available.
+ *
+ * @return whether the confirmationUI HAL is available.
+ */
+ public boolean isConfirmationPromptSupported() {
+ try {
+ return getService().isSupported();
+ } catch (RemoteException e) {
+ Log.w(TAG, "Cannot connect to keystore", e);
+ return false;
+ }
+ }
+
+}
diff --git a/keystore/java/android/security/IKeyChainService.aidl b/keystore/java/android/security/IKeyChainService.aidl
index a9d4094..f708298 100644
--- a/keystore/java/android/security/IKeyChainService.aidl
+++ b/keystore/java/android/security/IKeyChainService.aidl
@@ -60,7 +60,6 @@
byte[] getEncodedCaCertificate(String alias, boolean includeDeletedSystem);
List<String> getCaCertificateChainAliases(String rootAlias, boolean includeDeletedSystem);
void setCredentialManagementApp(String packageName, in AppUriAuthenticationPolicy policy);
- void updateCredentialManagementAppPolicy(in AppUriAuthenticationPolicy policy);
boolean hasCredentialManagementApp();
String getCredentialManagementAppPackageName();
AppUriAuthenticationPolicy getCredentialManagementAppPolicy();
diff --git a/keystore/java/android/security/KeyChain.java b/keystore/java/android/security/KeyChain.java
index c6e72b0..2f444b3 100644
--- a/keystore/java/android/security/KeyChain.java
+++ b/keystore/java/android/security/KeyChain.java
@@ -31,6 +31,7 @@
import android.content.ServiceConnection;
import android.net.Uri;
import android.os.Binder;
+import android.os.Handler;
import android.os.IBinder;
import android.os.Looper;
import android.os.Process;
@@ -854,10 +855,26 @@
@WorkerThread
public static KeyChainConnection bindAsUser(@NonNull Context context, UserHandle user)
throws InterruptedException {
+ return bindAsUser(context, null, user);
+ }
+
+ /**
+ * Bind to KeyChainService in the target user.
+ * Caller should call unbindService on the result when finished.
+ *
+ * @throws InterruptedException if interrupted during binding.
+ * @throws AssertionError if unable to bind to KeyChainService.
+ * @hide
+ */
+ public static KeyChainConnection bindAsUser(@NonNull Context context, @Nullable Handler handler,
+ UserHandle user) throws InterruptedException {
+
if (context == null) {
throw new NullPointerException("context == null");
}
- ensureNotOnMainThread(context);
+ if (handler == null) {
+ ensureNotOnMainThread(context);
+ }
if (!UserManager.get(context).isUserUnlocked(user)) {
throw new IllegalStateException("User must be unlocked");
}
@@ -884,9 +901,19 @@
};
Intent intent = new Intent(IKeyChainService.class.getName());
ComponentName comp = intent.resolveSystemService(context.getPackageManager(), 0);
+ if (comp == null) {
+ throw new AssertionError("could not resolve KeyChainService");
+ }
intent.setComponent(comp);
- if (comp == null || !context.bindServiceAsUser(
- intent, keyChainServiceConnection, Context.BIND_AUTO_CREATE, user)) {
+ final boolean bindSucceed;
+ if (handler != null) {
+ bindSucceed = context.bindServiceAsUser(
+ intent, keyChainServiceConnection, Context.BIND_AUTO_CREATE, handler, user);
+ } else {
+ bindSucceed = context.bindServiceAsUser(
+ intent, keyChainServiceConnection, Context.BIND_AUTO_CREATE, user);
+ }
+ if (!bindSucceed) {
throw new AssertionError("could not bind to KeyChainService");
}
countDownLatch.await();
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/legacysplitscreen/LegacySplitScreenController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/legacysplitscreen/LegacySplitScreenController.java
index d88696d..6b79a36 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/legacysplitscreen/LegacySplitScreenController.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/legacysplitscreen/LegacySplitScreenController.java
@@ -503,31 +503,31 @@
|| isSplitActive()) {
return false;
}
-
- // Try fetching the top running task.
- final List<RunningTaskInfo> runningTasks =
- ActivityTaskManager.getInstance().getTasks(1 /* maxNum */);
- if (runningTasks == null || runningTasks.isEmpty()) {
- return false;
- }
- // Note: The set of running tasks from the system is ordered by recency.
- final RunningTaskInfo topRunningTask = runningTasks.get(0);
- final int activityType = topRunningTask.getActivityType();
- if (activityType == ACTIVITY_TYPE_HOME || activityType == ACTIVITY_TYPE_RECENTS) {
- return false;
- }
-
- if (!topRunningTask.supportsSplitScreenMultiWindow) {
- Toast.makeText(mContext, R.string.dock_non_resizeble_failed_to_dock_text,
- Toast.LENGTH_SHORT).show();
- return false;
- }
-
- return ActivityTaskManager.getService().setTaskWindowingModeSplitScreenPrimary(
- topRunningTask.taskId, true /* onTop */);
} catch (RemoteException e) {
return false;
}
+
+ // Try fetching the top running task.
+ final List<RunningTaskInfo> runningTasks =
+ ActivityTaskManager.getInstance().getTasks(1 /* maxNum */);
+ if (runningTasks == null || runningTasks.isEmpty()) {
+ return false;
+ }
+ // Note: The set of running tasks from the system is ordered by recency.
+ final RunningTaskInfo topRunningTask = runningTasks.get(0);
+ final int activityType = topRunningTask.getActivityType();
+ if (activityType == ACTIVITY_TYPE_HOME || activityType == ACTIVITY_TYPE_RECENTS) {
+ return false;
+ }
+
+ if (!topRunningTask.supportsSplitScreenMultiWindow) {
+ Toast.makeText(mContext, R.string.dock_non_resizeble_failed_to_dock_text,
+ Toast.LENGTH_SHORT).show();
+ return false;
+ }
+
+ return ActivityTaskManager.getInstance().setTaskWindowingModeSplitScreenPrimary(
+ topRunningTask.taskId, true /* onTop */);
}
@Override
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/TaskSnapshotWindow.java b/libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/TaskSnapshotWindow.java
index e66d85f..3198725 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/TaskSnapshotWindow.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/TaskSnapshotWindow.java
@@ -221,8 +221,7 @@
mainExecutor.execute(() -> {
try {
final int res = session.addToDisplay(window, layoutParams, View.GONE,
- displayId, mTmpInsetsState, tmpFrames.frame,
- tmpFrames.displayCutout, tmpInputChannel/* outInputChannel */,
+ displayId, mTmpInsetsState, tmpFrames.frame, tmpInputChannel,
mTmpInsetsState, mTempControls);
if (res < 0) {
Slog.w(TAG, "Failed to add snapshot starting window res=" + res);
diff --git a/libs/hwui/RecordingCanvas.cpp b/libs/hwui/RecordingCanvas.cpp
index a2028ca..6bf2e99 100644
--- a/libs/hwui/RecordingCanvas.cpp
+++ b/libs/hwui/RecordingCanvas.cpp
@@ -306,25 +306,29 @@
struct DrawImage final : Op {
static const auto kType = Type::DrawImage;
- DrawImage(sk_sp<const SkImage>&& image, SkScalar x, SkScalar y, const SkPaint* paint,
- BitmapPalette palette)
- : image(std::move(image)), x(x), y(y), palette(palette) {
+ DrawImage(sk_sp<const SkImage>&& image, SkScalar x, SkScalar y,
+ const SkSamplingOptions& sampling, const SkPaint* paint, BitmapPalette palette)
+ : image(std::move(image)), x(x), y(y), sampling(sampling), palette(palette) {
if (paint) {
this->paint = *paint;
}
}
sk_sp<const SkImage> image;
SkScalar x, y;
+ SkSamplingOptions sampling;
SkPaint paint;
BitmapPalette palette;
- void draw(SkCanvas* c, const SkMatrix&) const { c->drawImage(image.get(), x, y, &paint); }
+ void draw(SkCanvas* c, const SkMatrix&) const {
+ c->drawImage(image.get(), x, y, sampling, &paint);
+ }
};
struct DrawImageRect final : Op {
static const auto kType = Type::DrawImageRect;
DrawImageRect(sk_sp<const SkImage>&& image, const SkRect* src, const SkRect& dst,
- const SkPaint* paint, SkCanvas::SrcRectConstraint constraint,
- BitmapPalette palette)
- : image(std::move(image)), dst(dst), constraint(constraint), palette(palette) {
+ const SkSamplingOptions& sampling, const SkPaint* paint,
+ SkCanvas::SrcRectConstraint constraint, BitmapPalette palette)
+ : image(std::move(image)), dst(dst), sampling(sampling), constraint(constraint)
+ , palette(palette) {
this->src = src ? *src : SkRect::MakeIWH(this->image->width(), this->image->height());
if (paint) {
this->paint = *paint;
@@ -332,23 +336,26 @@
}
sk_sp<const SkImage> image;
SkRect src, dst;
+ SkSamplingOptions sampling;
SkPaint paint;
SkCanvas::SrcRectConstraint constraint;
BitmapPalette palette;
void draw(SkCanvas* c, const SkMatrix&) const {
- c->drawImageRect(image.get(), src, dst, &paint, constraint);
+ c->drawImageRect(image.get(), src, dst, sampling, &paint, constraint);
}
};
struct DrawImageLattice final : Op {
static const auto kType = Type::DrawImageLattice;
DrawImageLattice(sk_sp<const SkImage>&& image, int xs, int ys, int fs, const SkIRect& src,
- const SkRect& dst, const SkPaint* paint, BitmapPalette palette)
+ const SkRect& dst, SkFilterMode filter, const SkPaint* paint,
+ BitmapPalette palette)
: image(std::move(image))
, xs(xs)
, ys(ys)
, fs(fs)
, src(src)
, dst(dst)
+ , filter(filter)
, palette(palette) {
if (paint) {
this->paint = *paint;
@@ -358,6 +365,7 @@
int xs, ys, fs;
SkIRect src;
SkRect dst;
+ SkFilterMode filter;
SkPaint paint;
BitmapPalette palette;
void draw(SkCanvas* c, const SkMatrix&) const {
@@ -366,7 +374,8 @@
auto flags =
(0 == fs) ? nullptr : pod<SkCanvas::Lattice::RectType>(
this, (xs + ys) * sizeof(int) + fs * sizeof(SkColor));
- c->drawImageLattice(image.get(), {xdivs, ydivs, flags, xs, ys, &src, colors}, dst, &paint);
+ c->drawImageLattice(image.get(), {xdivs, ydivs, flags, xs, ys, &src, colors}, dst,
+ filter, &paint);
}
};
@@ -431,9 +440,10 @@
};
struct DrawAtlas final : Op {
static const auto kType = Type::DrawAtlas;
- DrawAtlas(const SkImage* atlas, int count, SkBlendMode xfermode, const SkRect* cull,
- const SkPaint* paint, bool has_colors)
- : atlas(sk_ref_sp(atlas)), count(count), xfermode(xfermode), has_colors(has_colors) {
+ DrawAtlas(const SkImage* atlas, int count, SkBlendMode mode, const SkSamplingOptions& sampling,
+ const SkRect* cull, const SkPaint* paint, bool has_colors)
+ : atlas(sk_ref_sp(atlas)), count(count), mode(mode), sampling(sampling)
+ , has_colors(has_colors) {
if (cull) {
this->cull = *cull;
}
@@ -443,7 +453,8 @@
}
sk_sp<const SkImage> atlas;
int count;
- SkBlendMode xfermode;
+ SkBlendMode mode;
+ SkSamplingOptions sampling;
SkRect cull = kUnset;
SkPaint paint;
bool has_colors;
@@ -452,7 +463,8 @@
auto texs = pod<SkRect>(this, count * sizeof(SkRSXform));
auto colors = has_colors ? pod<SkColor>(this, count * (sizeof(SkRSXform) + sizeof(SkRect)))
: nullptr;
- c->drawAtlas(atlas.get(), xforms, texs, colors, count, xfermode, maybe_unset(cull), &paint);
+ c->drawAtlas(atlas.get(), xforms, texs, colors, count, mode, sampling, maybe_unset(cull),
+ &paint);
}
};
struct DrawShadowRec final : Op {
@@ -613,16 +625,18 @@
this->push<DrawPicture>(0, picture, matrix, paint);
}
void DisplayListData::drawImage(sk_sp<const SkImage> image, SkScalar x, SkScalar y,
- const SkPaint* paint, BitmapPalette palette) {
- this->push<DrawImage>(0, std::move(image), x, y, paint, palette);
+ const SkSamplingOptions& sampling, const SkPaint* paint,
+ BitmapPalette palette) {
+ this->push<DrawImage>(0, std::move(image), x, y, sampling, paint, palette);
}
void DisplayListData::drawImageRect(sk_sp<const SkImage> image, const SkRect* src,
- const SkRect& dst, const SkPaint* paint,
- SkCanvas::SrcRectConstraint constraint, BitmapPalette palette) {
- this->push<DrawImageRect>(0, std::move(image), src, dst, paint, constraint, palette);
+ const SkRect& dst, const SkSamplingOptions& sampling,
+ const SkPaint* paint, SkCanvas::SrcRectConstraint constraint,
+ BitmapPalette palette) {
+ this->push<DrawImageRect>(0, std::move(image), src, dst, sampling, paint, constraint, palette);
}
void DisplayListData::drawImageLattice(sk_sp<const SkImage> image, const SkCanvas::Lattice& lattice,
- const SkRect& dst, const SkPaint* paint,
+ const SkRect& dst, SkFilterMode filter, const SkPaint* paint,
BitmapPalette palette) {
int xs = lattice.fXCount, ys = lattice.fYCount;
int fs = lattice.fRectTypes ? (xs + 1) * (ys + 1) : 0;
@@ -630,7 +644,7 @@
fs * sizeof(SkColor);
SkASSERT(lattice.fBounds);
void* pod = this->push<DrawImageLattice>(bytes, std::move(image), xs, ys, fs, *lattice.fBounds,
- dst, paint, palette);
+ dst, filter, paint, palette);
copy_v(pod, lattice.fXDivs, xs, lattice.fYDivs, ys, lattice.fColors, fs, lattice.fRectTypes,
fs);
}
@@ -650,18 +664,19 @@
void* pod = this->push<DrawPoints>(count * sizeof(SkPoint), mode, count, paint);
copy_v(pod, points, count);
}
-void DisplayListData::drawVertices(const SkVertices* vertices, SkBlendMode mode, const SkPaint& paint) {
- this->push<DrawVertices>(0, vertices, mode, paint);
+void DisplayListData::drawVertices(const SkVertices* vert, SkBlendMode mode, const SkPaint& paint) {
+ this->push<DrawVertices>(0, vert, mode, paint);
}
void DisplayListData::drawAtlas(const SkImage* atlas, const SkRSXform xforms[], const SkRect texs[],
const SkColor colors[], int count, SkBlendMode xfermode,
- const SkRect* cull, const SkPaint* paint) {
+ const SkSamplingOptions& sampling, const SkRect* cull,
+ const SkPaint* paint) {
size_t bytes = count * (sizeof(SkRSXform) + sizeof(SkRect));
if (colors) {
bytes += count * sizeof(SkColor);
}
- void* pod =
- this->push<DrawAtlas>(bytes, atlas, count, xfermode, cull, paint, colors != nullptr);
+ void* pod = this->push<DrawAtlas>(bytes, atlas, count, xfermode, sampling, cull, paint,
+ colors != nullptr);
copy_v(pod, xforms, count, texs, count, colors, colors ? count : 0);
}
void DisplayListData::drawShadowRec(const SkPath& path, const SkDrawShadowRec& rec) {
@@ -887,18 +902,20 @@
}
void RecordingCanvas::drawImage(const sk_sp<SkImage>& image, SkScalar x, SkScalar y,
- const SkPaint* paint, BitmapPalette palette) {
- fDL->drawImage(image, x, y, paint, palette);
+ const SkSamplingOptions& sampling, const SkPaint* paint,
+ BitmapPalette palette) {
+ fDL->drawImage(image, x, y, sampling, paint, palette);
}
void RecordingCanvas::drawImageRect(const sk_sp<SkImage>& image, const SkRect& src,
- const SkRect& dst, const SkPaint* paint,
- SrcRectConstraint constraint, BitmapPalette palette) {
- fDL->drawImageRect(image, &src, dst, paint, constraint, palette);
+ const SkRect& dst, const SkSamplingOptions& sampling,
+ const SkPaint* paint, SrcRectConstraint constraint,
+ BitmapPalette palette) {
+ fDL->drawImageRect(image, &src, dst, sampling, paint, constraint, palette);
}
void RecordingCanvas::drawImageLattice(const sk_sp<SkImage>& image, const Lattice& lattice,
- const SkRect& dst, const SkPaint* paint,
+ const SkRect& dst, SkFilterMode filter, const SkPaint* paint,
BitmapPalette palette) {
if (!image || dst.isEmpty()) {
return;
@@ -912,24 +929,29 @@
}
if (SkLatticeIter::Valid(image->width(), image->height(), latticePlusBounds)) {
- fDL->drawImageLattice(image, latticePlusBounds, dst, paint, palette);
+ fDL->drawImageLattice(image, latticePlusBounds, dst, filter, paint, palette);
} else {
- fDL->drawImageRect(image, nullptr, dst, paint, SrcRectConstraint::kFast_SrcRectConstraint,
- palette);
+ SkSamplingOptions sampling(filter, SkMipmapMode::kNone);
+ fDL->drawImageRect(image, nullptr, dst, sampling, paint, kFast_SrcRectConstraint, palette);
}
}
-void RecordingCanvas::onDrawImage(const SkImage* img, SkScalar x, SkScalar y,
- const SkPaint* paint) {
- fDL->drawImage(sk_ref_sp(img), x, y, paint, BitmapPalette::Unknown);
+void RecordingCanvas::onDrawImage2(const SkImage* img, SkScalar x, SkScalar y,
+ const SkSamplingOptions& sampling, const SkPaint* paint) {
+ fDL->drawImage(sk_ref_sp(img), x, y, sampling, paint, BitmapPalette::Unknown);
}
-void RecordingCanvas::onDrawImageRect(const SkImage* img, const SkRect* src, const SkRect& dst,
- const SkPaint* paint, SrcRectConstraint constraint) {
- fDL->drawImageRect(sk_ref_sp(img), src, dst, paint, constraint, BitmapPalette::Unknown);
+
+void RecordingCanvas::onDrawImageRect2(const SkImage* img, const SkRect& src, const SkRect& dst,
+ const SkSamplingOptions& sampling, const SkPaint* paint,
+ SrcRectConstraint constraint) {
+ fDL->drawImageRect(sk_ref_sp(img), &src, dst, sampling, paint, constraint,
+ BitmapPalette::Unknown);
}
-void RecordingCanvas::onDrawImageLattice(const SkImage* img, const SkCanvas::Lattice& lattice,
- const SkRect& dst, const SkPaint* paint) {
- fDL->drawImageLattice(sk_ref_sp(img), lattice, dst, paint, BitmapPalette::Unknown);
+
+void RecordingCanvas::onDrawImageLattice2(const SkImage* img, const SkCanvas::Lattice& lattice,
+ const SkRect& dst, SkFilterMode filter,
+ const SkPaint* paint) {
+ fDL->drawImageLattice(sk_ref_sp(img), lattice, dst, filter, paint, BitmapPalette::Unknown);
}
void RecordingCanvas::onDrawPatch(const SkPoint cubics[12], const SkColor colors[4],
@@ -945,10 +967,11 @@
SkBlendMode mode, const SkPaint& paint) {
fDL->drawVertices(vertices, mode, paint);
}
-void RecordingCanvas::onDrawAtlas(const SkImage* atlas, const SkRSXform xforms[],
- const SkRect texs[], const SkColor colors[], int count,
- SkBlendMode bmode, const SkRect* cull, const SkPaint* paint) {
- fDL->drawAtlas(atlas, xforms, texs, colors, count, bmode, cull, paint);
+void RecordingCanvas::onDrawAtlas2(const SkImage* atlas, const SkRSXform xforms[],
+ const SkRect texs[], const SkColor colors[], int count,
+ SkBlendMode bmode, const SkSamplingOptions& sampling,
+ const SkRect* cull, const SkPaint* paint) {
+ fDL->drawAtlas(atlas, xforms, texs, colors, count, bmode, sampling, cull, paint);
}
void RecordingCanvas::onDrawShadowRec(const SkPath& path, const SkDrawShadowRec& rec) {
fDL->drawShadowRec(path, rec);
diff --git a/libs/hwui/RecordingCanvas.h b/libs/hwui/RecordingCanvas.h
index 9e2b0a9..89e3df7 100644
--- a/libs/hwui/RecordingCanvas.h
+++ b/libs/hwui/RecordingCanvas.h
@@ -108,19 +108,20 @@
void drawTextBlob(const SkTextBlob*, SkScalar, SkScalar, const SkPaint&);
- void drawImage(sk_sp<const SkImage>, SkScalar, SkScalar, const SkPaint*, BitmapPalette palette);
+ void drawImage(sk_sp<const SkImage>, SkScalar, SkScalar, const SkSamplingOptions&,
+ const SkPaint*, BitmapPalette palette);
void drawImageNine(sk_sp<const SkImage>, const SkIRect&, const SkRect&, const SkPaint*);
- void drawImageRect(sk_sp<const SkImage>, const SkRect*, const SkRect&, const SkPaint*,
- SkCanvas::SrcRectConstraint, BitmapPalette palette);
+ void drawImageRect(sk_sp<const SkImage>, const SkRect*, const SkRect&, const SkSamplingOptions&,
+ const SkPaint*, SkCanvas::SrcRectConstraint, BitmapPalette palette);
void drawImageLattice(sk_sp<const SkImage>, const SkCanvas::Lattice&, const SkRect&,
- const SkPaint*, BitmapPalette);
+ SkFilterMode, const SkPaint*, BitmapPalette);
void drawPatch(const SkPoint[12], const SkColor[4], const SkPoint[4], SkBlendMode,
const SkPaint&);
void drawPoints(SkCanvas::PointMode, size_t, const SkPoint[], const SkPaint&);
void drawVertices(const SkVertices*, SkBlendMode, const SkPaint&);
void drawAtlas(const SkImage*, const SkRSXform[], const SkRect[], const SkColor[], int,
- SkBlendMode, const SkRect*, const SkPaint*);
+ SkBlendMode, const SkSamplingOptions&, const SkRect*, const SkPaint*);
void drawShadowRec(const SkPath&, const SkDrawShadowRec&);
void drawVectorDrawable(VectorDrawableRoot* tree);
void drawWebView(skiapipeline::FunctorDrawable*);
@@ -178,25 +179,27 @@
void onDrawTextBlob(const SkTextBlob*, SkScalar, SkScalar, const SkPaint&) override;
- void drawImage(const sk_sp<SkImage>& image, SkScalar left, SkScalar top, const SkPaint* paint,
- BitmapPalette pallete);
+ void drawImage(const sk_sp<SkImage>&, SkScalar left, SkScalar top, const SkSamplingOptions&,
+ const SkPaint* paint, BitmapPalette pallete);
void drawImageRect(const sk_sp<SkImage>& image, const SkRect& src, const SkRect& dst,
- const SkPaint* paint, SrcRectConstraint constraint, BitmapPalette palette);
+ const SkSamplingOptions&, const SkPaint*, SrcRectConstraint, BitmapPalette);
void drawImageLattice(const sk_sp<SkImage>& image, const Lattice& lattice, const SkRect& dst,
- const SkPaint* paint, BitmapPalette palette);
+ SkFilterMode, const SkPaint* paint, BitmapPalette palette);
- void onDrawImage(const SkImage*, SkScalar, SkScalar, const SkPaint*) override;
- void onDrawImageLattice(const SkImage*, const Lattice&, const SkRect&, const SkPaint*) override;
- void onDrawImageRect(const SkImage*, const SkRect*, const SkRect&, const SkPaint*,
- SrcRectConstraint) override;
+ void onDrawImage2(const SkImage*, SkScalar, SkScalar, const SkSamplingOptions&,
+ const SkPaint*) override;
+ void onDrawImageLattice2(const SkImage*, const Lattice&, const SkRect&, SkFilterMode,
+ const SkPaint*) override;
+ void onDrawImageRect2(const SkImage*, const SkRect&, const SkRect&, const SkSamplingOptions&,
+ const SkPaint*, SrcRectConstraint) override;
void onDrawPatch(const SkPoint[12], const SkColor[4], const SkPoint[4], SkBlendMode,
const SkPaint&) override;
void onDrawPoints(PointMode, size_t count, const SkPoint pts[], const SkPaint&) override;
void onDrawVerticesObject(const SkVertices*, SkBlendMode, const SkPaint&) override;
- void onDrawAtlas(const SkImage*, const SkRSXform[], const SkRect[], const SkColor[], int,
- SkBlendMode, const SkRect*, const SkPaint*) override;
+ void onDrawAtlas2(const SkImage*, const SkRSXform[], const SkRect[], const SkColor[], int,
+ SkBlendMode, const SkSamplingOptions&, const SkRect*, const SkPaint*) override;
void onDrawShadowRec(const SkPath&, const SkDrawShadowRec&) override;
void drawVectorDrawable(VectorDrawableRoot* tree);
diff --git a/libs/hwui/SkiaCanvas.h b/libs/hwui/SkiaCanvas.h
index 591ae5c..584321e 100644
--- a/libs/hwui/SkiaCanvas.h
+++ b/libs/hwui/SkiaCanvas.h
@@ -190,7 +190,6 @@
}
operator const SkPaint*() const { return mPtr; }
const SkPaint* operator->() const { assert(mPtr); return mPtr; }
- const SkPaint& operator*() const { assert(mPtr); return *mPtr; }
explicit operator bool() { return mPtr != nullptr; }
private:
const SkPaint* mPtr;
diff --git a/libs/hwui/pipeline/skia/DumpOpsCanvas.h b/libs/hwui/pipeline/skia/DumpOpsCanvas.h
index d5b46d5..26ff8bf 100644
--- a/libs/hwui/pipeline/skia/DumpOpsCanvas.h
+++ b/libs/hwui/pipeline/skia/DumpOpsCanvas.h
@@ -86,17 +86,18 @@
mOutput << mIdent << "drawTextBlob" << std::endl;
}
- void onDrawImage(const SkImage*, SkScalar dx, SkScalar dy, const SkPaint*) override {
+ void onDrawImage2(const SkImage*, SkScalar dx, SkScalar dy, const SkSamplingOptions&,
+ const SkPaint*) override {
mOutput << mIdent << "drawImage" << std::endl;
}
- void onDrawImageRect(const SkImage*, const SkRect*, const SkRect&, const SkPaint*,
- SrcRectConstraint) override {
+ void onDrawImageRect2(const SkImage*, const SkRect&, const SkRect&, const SkSamplingOptions&,
+ const SkPaint*, SrcRectConstraint) override {
mOutput << mIdent << "drawImageRect" << std::endl;
}
- void onDrawImageLattice(const SkImage*, const Lattice& lattice, const SkRect& dst,
- const SkPaint*) override {
+ void onDrawImageLattice2(const SkImage*, const Lattice& lattice, const SkRect& dst,
+ SkFilterMode, const SkPaint*) override {
mOutput << mIdent << "drawImageLattice" << std::endl;
}
diff --git a/libs/hwui/pipeline/skia/SkiaRecordingCanvas.cpp b/libs/hwui/pipeline/skia/SkiaRecordingCanvas.cpp
index e292cbd..a436278 100644
--- a/libs/hwui/pipeline/skia/SkiaRecordingCanvas.cpp
+++ b/libs/hwui/pipeline/skia/SkiaRecordingCanvas.cpp
@@ -185,18 +185,21 @@
}
template <typename Proc>
-void applyLooper(SkDrawLooper* looper, const SkPaint& paint, Proc proc) {
+void applyLooper(SkDrawLooper* looper, const SkPaint* paint, Proc proc) {
if (looper) {
SkSTArenaAlloc<256> alloc;
SkDrawLooper::Context* ctx = looper->makeContext(&alloc);
if (ctx) {
SkDrawLooper::Context::Info info;
for (;;) {
- SkPaint p = paint;
+ SkPaint p;
+ if (paint) {
+ p = *paint;
+ }
if (!ctx->next(&info, &p)) {
break;
}
- proc(info.fTranslate.fX, info.fTranslate.fY, p);
+ proc(info.fTranslate.fX, info.fTranslate.fY, &p);
}
}
} else {
@@ -204,11 +207,22 @@
}
}
+static SkFilterMode Paint_to_filter(const SkPaint* paint) {
+ return paint && paint->getFilterQuality() != kNone_SkFilterQuality ? SkFilterMode::kLinear
+ : SkFilterMode::kNearest;
+}
+
+static SkSamplingOptions Paint_to_sampling(const SkPaint* paint) {
+ // Android only has 1-bit for "filter", so we don't try to cons-up mipmaps or cubics
+ return SkSamplingOptions(Paint_to_filter(paint), SkMipmapMode::kNone);
+}
+
void SkiaRecordingCanvas::drawBitmap(Bitmap& bitmap, float left, float top, const Paint* paint) {
sk_sp<SkImage> image = bitmap.makeImage();
- applyLooper(get_looper(paint), *filterBitmap(paint), [&](SkScalar x, SkScalar y, const SkPaint& p) {
- mRecorder.drawImage(image, left + x, top + y, &p, bitmap.palette());
+ applyLooper(get_looper(paint), filterBitmap(paint), [&](SkScalar x, SkScalar y,
+ const SkPaint* p) {
+ mRecorder.drawImage(image, left + x, top + y, Paint_to_sampling(p), p, bitmap.palette());
});
// if image->unique() is true, then mRecorder.drawImage failed for some reason. It also means
@@ -225,8 +239,9 @@
sk_sp<SkImage> image = bitmap.makeImage();
- applyLooper(get_looper(paint), *filterBitmap(paint), [&](SkScalar x, SkScalar y, const SkPaint& p) {
- mRecorder.drawImage(image, x, y, &p, bitmap.palette());
+ applyLooper(get_looper(paint), filterBitmap(paint), [&](SkScalar x, SkScalar y,
+ const SkPaint* p) {
+ mRecorder.drawImage(image, x, y, Paint_to_sampling(p), p, bitmap.palette());
});
if (!bitmap.isImmutable() && image.get() && !image->unique()) {
@@ -242,9 +257,10 @@
sk_sp<SkImage> image = bitmap.makeImage();
- applyLooper(get_looper(paint), *filterBitmap(paint), [&](SkScalar x, SkScalar y, const SkPaint& p) {
- mRecorder.drawImageRect(image, srcRect, dstRect.makeOffset(x, y), &p,
- SkCanvas::kFast_SrcRectConstraint, bitmap.palette());
+ applyLooper(get_looper(paint), filterBitmap(paint), [&](SkScalar x, SkScalar y,
+ const SkPaint* p) {
+ mRecorder.drawImageRect(image, srcRect, dstRect.makeOffset(x, y), Paint_to_sampling(p),
+ p, SkCanvas::kFast_SrcRectConstraint, bitmap.palette());
});
if (!bitmap.isImmutable() && image.get() && !image->unique() && !srcRect.isEmpty() &&
@@ -276,16 +292,12 @@
lattice.fBounds = nullptr;
SkRect dst = SkRect::MakeLTRB(dstLeft, dstTop, dstRight, dstBottom);
-
- PaintCoW filteredPaint(paint);
- // HWUI always draws 9-patches with bilinear filtering, regardless of what is set in the Paint.
- if (!filteredPaint || filteredPaint->getFilterQuality() != kLow_SkFilterQuality) {
- filteredPaint.writeable().setFilterQuality(kLow_SkFilterQuality);
- }
sk_sp<SkImage> image = bitmap.makeImage();
- applyLooper(get_looper(paint), *filterBitmap(paint), [&](SkScalar x, SkScalar y, const SkPaint& p) {
- mRecorder.drawImageLattice(image, lattice, dst.makeOffset(x, y), &p, bitmap.palette());
+ applyLooper(get_looper(paint), filterBitmap(paint), [&](SkScalar x, SkScalar y,
+ const SkPaint* p) {
+ mRecorder.drawImageLattice(image, lattice, dst.makeOffset(x, y), Paint_to_filter(p),
+ p, bitmap.palette());
});
if (!bitmap.isImmutable() && image.get() && !image->unique() && !dst.isEmpty()) {
diff --git a/libs/hwui/tests/common/CallCountingCanvas.h b/libs/hwui/tests/common/CallCountingCanvas.h
index 40b5747..d3c41191 100644
--- a/libs/hwui/tests/common/CallCountingCanvas.h
+++ b/libs/hwui/tests/common/CallCountingCanvas.h
@@ -108,27 +108,27 @@
}
int drawImageCount = 0;
- void onDrawImage(const SkImage* image, SkScalar dx, SkScalar dy,
+ void onDrawImage2(const SkImage* image, SkScalar dx, SkScalar dy, const SkSamplingOptions&,
const SkPaint* paint) override {
drawImageCount++;
}
int drawImageRectCount = 0;
- void onDrawImageRect(const SkImage* image, const SkRect* src, const SkRect& dst,
- const SkPaint* paint, SkCanvas::SrcRectConstraint constraint) override {
+ void onDrawImageRect2(const SkImage*, const SkRect&, const SkRect&, const SkSamplingOptions&,
+ const SkPaint*, SkCanvas::SrcRectConstraint) override {
drawImageRectCount++;
}
int drawImageLatticeCount = 0;
- void onDrawImageLattice(const SkImage* image, const SkCanvas::Lattice& lattice,
- const SkRect& dst, const SkPaint* paint) override {
+ void onDrawImageLattice2(const SkImage* image, const SkCanvas::Lattice& lattice,
+ const SkRect& dst, SkFilterMode, const SkPaint* paint) override {
drawImageLatticeCount++;
}
int drawAtlasCount = 0;
- void onDrawAtlas(const SkImage* atlas, const SkRSXform xform[], const SkRect rect[],
- const SkColor colors[], int count, SkBlendMode mode, const SkRect* cull,
- const SkPaint* paint) override {
+ void onDrawAtlas2(const SkImage* atlas, const SkRSXform xform[], const SkRect rect[],
+ const SkColor colors[], int count, SkBlendMode mode, const SkSamplingOptions&,
+ const SkRect* cull, const SkPaint* paint) override {
drawAtlasCount++;
}
diff --git a/libs/hwui/tests/unit/FatalTestCanvas.h b/libs/hwui/tests/unit/FatalTestCanvas.h
index 8467be9..2a74afc 100644
--- a/libs/hwui/tests/unit/FatalTestCanvas.h
+++ b/libs/hwui/tests/unit/FatalTestCanvas.h
@@ -60,22 +60,23 @@
void onDrawVerticesObject(const SkVertices*, SkBlendMode, const SkPaint&) {
ADD_FAILURE() << "onDrawVertices not expected in this test";
}
- void onDrawAtlas(const SkImage*, const SkRSXform[], const SkRect[], const SkColor[], int count,
- SkBlendMode, const SkRect* cull, const SkPaint*) {
+ void onDrawAtlas2(const SkImage*, const SkRSXform[], const SkRect[], const SkColor[], int count,
+ SkBlendMode, const SkSamplingOptions&, const SkRect* cull, const SkPaint*) {
ADD_FAILURE() << "onDrawAtlas not expected in this test";
}
void onDrawPath(const SkPath&, const SkPaint&) {
ADD_FAILURE() << "onDrawPath not expected in this test";
}
- void onDrawImage(const SkImage*, SkScalar dx, SkScalar dy, const SkPaint*) {
+ void onDrawImage2(const SkImage*, SkScalar dx, SkScalar dy, const SkSamplingOptions&,
+ const SkPaint*) {
ADD_FAILURE() << "onDrawImage not expected in this test";
}
- void onDrawImageRect(const SkImage*, const SkRect*, const SkRect&, const SkPaint*,
- SrcRectConstraint) {
+ void onDrawImageRect2(const SkImage*, const SkRect&, const SkRect&, const SkSamplingOptions&,
+ const SkPaint*, SrcRectConstraint) {
ADD_FAILURE() << "onDrawImageRect not expected in this test";
}
- void onDrawImageLattice(const SkImage*, const Lattice& lattice, const SkRect& dst,
- const SkPaint*) {
+ void onDrawImageLattice2(const SkImage*, const Lattice& lattice, const SkRect& dst,
+ SkFilterMode, const SkPaint*) {
ADD_FAILURE() << "onDrawImageLattice not expected in this test";
}
void onClipRRect(const SkRRect& rrect, SkClipOp, ClipEdgeStyle) {
diff --git a/libs/hwui/tests/unit/RenderNodeDrawableTests.cpp b/libs/hwui/tests/unit/RenderNodeDrawableTests.cpp
index 26bc659..423400e 100644
--- a/libs/hwui/tests/unit/RenderNodeDrawableTests.cpp
+++ b/libs/hwui/tests/unit/RenderNodeDrawableTests.cpp
@@ -938,7 +938,8 @@
void onDrawRect(const SkRect& rect, const SkPaint& paint) override {
EXPECT_EQ(0, mDrawCounter++);
}
- void onDrawImage(const SkImage*, SkScalar dx, SkScalar dy, const SkPaint*) override {
+ void onDrawImage2(const SkImage*, SkScalar dx, SkScalar dy, const SkSamplingOptions&,
+ const SkPaint*) override {
EXPECT_EQ(1, mDrawCounter++);
}
};
@@ -1047,7 +1048,7 @@
EXPECT_EQ(2, canvas.mDrawCounter);
}
-// Verify that layers are composed with kLow_SkFilterQuality filter quality.
+// Verify that layers are composed with linear filtering.
RENDERTHREAD_SKIA_PIPELINE_TEST(RenderNodeDrawable, layerComposeQuality) {
static const int CANVAS_WIDTH = 1;
static const int CANVAS_HEIGHT = 1;
@@ -1056,10 +1057,12 @@
class FrameTestCanvas : public TestCanvasBase {
public:
FrameTestCanvas() : TestCanvasBase(CANVAS_WIDTH, CANVAS_HEIGHT) {}
- void onDrawImageRect(const SkImage* image, const SkRect* src, const SkRect& dst,
- const SkPaint* paint, SrcRectConstraint constraint) override {
+ void onDrawImageRect2(const SkImage* image, const SkRect& src, const SkRect& dst,
+ const SkSamplingOptions& sampling, const SkPaint* paint,
+ SrcRectConstraint constraint) override {
mDrawCounter++;
- EXPECT_EQ(kLow_SkFilterQuality, paint->getFilterQuality());
+ EXPECT_FALSE(sampling.useCubic);
+ EXPECT_EQ(SkFilterMode::kLinear, sampling.filter);
}
};
@@ -1169,8 +1172,9 @@
class VectorDrawableTestCanvas : public TestCanvasBase {
public:
VectorDrawableTestCanvas() : TestCanvasBase(CANVAS_WIDTH, CANVAS_HEIGHT) {}
- void onDrawImageRect(const SkImage*, const SkRect* src, const SkRect& dst,
- const SkPaint* paint, SrcRectConstraint constraint) override {
+ void onDrawImageRect2(const SkImage*, const SkRect& src, const SkRect& dst,
+ const SkSamplingOptions&, const SkPaint* paint,
+ SrcRectConstraint constraint) override {
const int index = mDrawCounter++;
switch (index) {
case 0:
diff --git a/libs/hwui/tests/unit/SkiaPipelineTests.cpp b/libs/hwui/tests/unit/SkiaPipelineTests.cpp
index e7a889d..6dd57b1 100644
--- a/libs/hwui/tests/unit/SkiaPipelineTests.cpp
+++ b/libs/hwui/tests/unit/SkiaPipelineTests.cpp
@@ -302,7 +302,8 @@
class ClippedTestCanvas : public SkCanvas {
public:
ClippedTestCanvas() : SkCanvas(CANVAS_WIDTH, CANVAS_HEIGHT) {}
- void onDrawImage(const SkImage*, SkScalar dx, SkScalar dy, const SkPaint*) override {
+ void onDrawImage2(const SkImage*, SkScalar dx, SkScalar dy, const SkSamplingOptions&,
+ const SkPaint*) override {
EXPECT_EQ(0, mDrawCounter++);
EXPECT_EQ(SkRect::MakeLTRB(10, 20, 30, 40), TestUtils::getClipBounds(this));
EXPECT_TRUE(getTotalMatrix().isIdentity());
@@ -336,7 +337,8 @@
class ClippedTestCanvas : public SkCanvas {
public:
ClippedTestCanvas() : SkCanvas(CANVAS_WIDTH, CANVAS_HEIGHT) {}
- void onDrawImage(const SkImage*, SkScalar dx, SkScalar dy, const SkPaint*) override {
+ void onDrawImage2(const SkImage*, SkScalar dx, SkScalar dy, const SkSamplingOptions&,
+ const SkPaint*) override {
EXPECT_EQ(0, mDrawCounter++);
// Expect clip to be rotated.
EXPECT_EQ(SkRect::MakeLTRB(CANVAS_HEIGHT - dirty.fTop - dirty.height(), dirty.fLeft,
diff --git a/location/java/com/android/internal/location/timezone/LocationTimeZoneEvent.aidl b/location/java/android/location/GnssCapabilities.aidl
similarity index 87%
rename from location/java/com/android/internal/location/timezone/LocationTimeZoneEvent.aidl
rename to location/java/android/location/GnssCapabilities.aidl
index 199e067..bdf3014 100644
--- a/location/java/com/android/internal/location/timezone/LocationTimeZoneEvent.aidl
+++ b/location/java/android/location/GnssCapabilities.aidl
@@ -14,6 +14,6 @@
* limitations under the License.
*/
-package com.android.internal.location.timezone;
+package android.location;
-parcelable LocationTimeZoneEvent;
+parcelable GnssCapabilities;
\ No newline at end of file
diff --git a/location/java/android/location/GnssCapabilities.java b/location/java/android/location/GnssCapabilities.java
index bbb5bb8..89a3bd5 100644
--- a/location/java/android/location/GnssCapabilities.java
+++ b/location/java/android/location/GnssCapabilities.java
@@ -16,121 +16,207 @@
package android.location;
+import android.annotation.IntDef;
+import android.annotation.NonNull;
import android.annotation.SystemApi;
+import android.os.Parcel;
+import android.os.Parcelable;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.util.Objects;
+import java.util.concurrent.Executor;
/**
- * A container of supported GNSS chipset capabilities.
+ * GNSS chipset capabilities.
*/
-public final class GnssCapabilities {
- /**
- * Bit mask indicating GNSS chipset supports low power mode.
- * @hide
- */
- public static final long LOW_POWER_MODE = 1L << 0;
+public final class GnssCapabilities implements Parcelable {
- /**
- * Bit mask indicating GNSS chipset supports blocklisting satellites.
- * @hide
- */
- public static final long SATELLITE_BLOCKLIST = 1L << 1;
-
- /**
- * Bit mask indicating GNSS chipset supports geofencing.
- * @hide
- */
- public static final long GEOFENCING = 1L << 2;
-
- /**
- * Bit mask indicating GNSS chipset supports measurements.
- * @hide
- */
- public static final long MEASUREMENTS = 1L << 3;
-
- /**
- * Bit mask indicating GNSS chipset supports navigation messages.
- * @hide
- */
- public static final long NAV_MESSAGES = 1L << 4;
-
- /**
- * Bit mask indicating GNSS chipset supports measurement corrections.
- * @hide
- */
- public static final long MEASUREMENT_CORRECTIONS = 1L << 5;
-
- /**
- * Bit mask indicating GNSS chipset supports line-of-sight satellite identification
- * measurement corrections.
- * @hide
- */
- public static final long MEASUREMENT_CORRECTIONS_LOS_SATS = 1L << 6;
-
- /**
- * Bit mask indicating GNSS chipset supports per satellite excess-path-length
- * measurement corrections.
- * @hide
- */
- public static final long MEASUREMENT_CORRECTIONS_EXCESS_PATH_LENGTH = 1L << 7;
-
- /**
- * Bit mask indicating GNSS chipset supports reflecting planes measurement corrections.
- * @hide
- */
- public static final long MEASUREMENT_CORRECTIONS_REFLECTING_PLANE = 1L << 8;
-
- /**
- * Bit mask indicating GNSS chipset supports GNSS antenna info.
- * @hide
- */
- public static final long ANTENNA_INFO = 1L << 9;
+ // IMPORTANT - must match the Capabilities enum in IGnssCallback.hal
+ /** @hide */
+ public static final int TOP_HAL_CAPABILITY_SCHEDULING = 1;
+ /** @hide */
+ public static final int TOP_HAL_CAPABILITY_MSB = 2;
+ /** @hide */
+ public static final int TOP_HAL_CAPABILITY_MSA = 4;
+ /** @hide */
+ public static final int TOP_HAL_CAPABILITY_SINGLE_SHOT = 8;
+ /** @hide */
+ public static final int TOP_HAL_CAPABILITY_ON_DEMAND_TIME = 16;
+ /** @hide */
+ public static final int TOP_HAL_CAPABILITY_GEOFENCING = 32;
+ /** @hide */
+ public static final int TOP_HAL_CAPABILITY_MEASUREMENTS = 64;
+ /** @hide */
+ public static final int TOP_HAL_CAPABILITY_NAV_MESSAGES = 128;
+ /** @hide */
+ public static final int TOP_HAL_CAPABILITY_LOW_POWER_MODE = 256;
+ /** @hide */
+ public static final int TOP_HAL_CAPABILITY_SATELLITE_BLOCKLIST = 512;
+ /** @hide */
+ public static final int TOP_HAL_CAPABILITY_MEASUREMENT_CORRECTIONS = 1024;
+ /** @hide */
+ public static final int TOP_HAL_CAPABILITY_ANTENNA_INFO = 2048;
/** @hide */
- public static final long INVALID_CAPABILITIES = -1;
+ @IntDef(flag = true, prefix = {"TOP_HAL_CAPABILITY_"}, value = {TOP_HAL_CAPABILITY_SCHEDULING,
+ TOP_HAL_CAPABILITY_MSB, TOP_HAL_CAPABILITY_MSA, TOP_HAL_CAPABILITY_SINGLE_SHOT,
+ TOP_HAL_CAPABILITY_ON_DEMAND_TIME, TOP_HAL_CAPABILITY_GEOFENCING,
+ TOP_HAL_CAPABILITY_MEASUREMENTS, TOP_HAL_CAPABILITY_NAV_MESSAGES,
+ TOP_HAL_CAPABILITY_LOW_POWER_MODE, TOP_HAL_CAPABILITY_SATELLITE_BLOCKLIST,
+ TOP_HAL_CAPABILITY_MEASUREMENT_CORRECTIONS, TOP_HAL_CAPABILITY_ANTENNA_INFO})
+ @Retention(RetentionPolicy.SOURCE)
+ public @interface TopHalCapabilityFlags {}
- /** A bitmask of supported GNSS capabilities. */
- private final long mGnssCapabilities;
+ // IMPORTANT - must match the Capabilities enum in IMeasurementCorrectionsCallback.hal
+ /** @hide */
+ public static final int SUB_HAL_MEASUREMENT_CORRECTIONS_CAPABILITY_LOS_SATS = 1;
+ /** @hide */
+ public static final int SUB_HAL_MEASUREMENT_CORRECTIONS_CAPABILITY_EXCESS_PATH_LENGTH = 2;
+ /** @hide */
+ public static final int SUB_HAL_MEASUREMENT_CORRECTIONS_CAPABILITY_REFLECTING_PLANE = 4;
/** @hide */
- public static GnssCapabilities of(long gnssCapabilities) {
- return new GnssCapabilities(gnssCapabilities);
- }
+ @IntDef(flag = true, prefix = {"SUB_HAL_MEASUREMENT_CORRECTIONS_CAPABILITY_"}, value = {
+ SUB_HAL_MEASUREMENT_CORRECTIONS_CAPABILITY_LOS_SATS,
+ SUB_HAL_MEASUREMENT_CORRECTIONS_CAPABILITY_EXCESS_PATH_LENGTH,
+ SUB_HAL_MEASUREMENT_CORRECTIONS_CAPABILITY_REFLECTING_PLANE})
+ @Retention(RetentionPolicy.SOURCE)
+ public @interface SubHalMeasurementCorrectionsCapabilityFlags {}
- private GnssCapabilities(long gnssCapabilities) {
- mGnssCapabilities = gnssCapabilities;
- }
+ // IMPORATANT - must match values in IGnssPowerIndicationCallback.aidl
+ /** @hide */
+ public static final int SUB_HAL_POWER_CAPABILITY_TOTAL = 1;
+ /** @hide */
+ public static final int SUB_HAL_POWER_CAPABILITY_SINGLEBAND_TRACKING = 2;
+ /** @hide */
+ public static final int SUB_HAL_POWER_CAPABILITY_MULTIBAND_TRACKING = 4;
+ /** @hide */
+ public static final int SUB_HAL_POWER_CAPABILITY_SINGLEBAND_ACQUISITION = 8;
+ /** @hide */
+ public static final int SUB_HAL_POWER_CAPABILITY_MULTIBAND_ACQUISITION = 16;
+ /** @hide */
+ public static final int SUB_HAL_POWER_CAPABILITY_OTHER_MODES = 32;
+
+ /** @hide */
+ @IntDef(flag = true, prefix = {"SUB_HAL_POWER_CAPABILITY_"}, value = {
+ SUB_HAL_POWER_CAPABILITY_TOTAL, SUB_HAL_POWER_CAPABILITY_SINGLEBAND_TRACKING,
+ SUB_HAL_POWER_CAPABILITY_MULTIBAND_TRACKING,
+ SUB_HAL_POWER_CAPABILITY_SINGLEBAND_ACQUISITION,
+ SUB_HAL_POWER_CAPABILITY_MULTIBAND_ACQUISITION,
+ SUB_HAL_POWER_CAPABILITY_OTHER_MODES})
+ @Retention(RetentionPolicy.SOURCE)
+ public @interface SubHalPowerCapabilityFlags {}
/**
- * Returns {@code true} if GNSS chipset supports low power mode, {@code false} otherwise.
+ * Returns an empty GnssCapabilities object.
*
* @hide
*/
- @SystemApi
- public boolean hasLowPowerMode() {
- return hasCapability(LOW_POWER_MODE);
+ public static GnssCapabilities empty() {
+ return new GnssCapabilities(0, 0, 0);
+ }
+
+ private final @TopHalCapabilityFlags int mTopFlags;
+ private final @SubHalMeasurementCorrectionsCapabilityFlags int mMeasurementCorrectionsFlags;
+ private final @SubHalPowerCapabilityFlags int mPowerFlags;
+
+ private GnssCapabilities(
+ @TopHalCapabilityFlags int topFlags,
+ @SubHalMeasurementCorrectionsCapabilityFlags int measurementCorrectionsFlags,
+ @SubHalPowerCapabilityFlags int powerFlags) {
+ mTopFlags = topFlags;
+ mMeasurementCorrectionsFlags = measurementCorrectionsFlags;
+ mPowerFlags = powerFlags;
}
/**
- * Returns {@code true} if GNSS chipset supports blocklisting satellites, {@code false}
- * otherwise.
+ * Returns a new GnssCapabilities object with top hal values set from the given flags.
*
* @hide
- * @deprecated use {@link #hasSatelliteBlocklist} instead.
*/
- @SystemApi
- @Deprecated
- public boolean hasSatelliteBlacklist() {
- return hasCapability(SATELLITE_BLOCKLIST);
+ public GnssCapabilities withTopHalFlags(@TopHalCapabilityFlags int flags) {
+ if (mTopFlags == flags) {
+ return this;
+ } else {
+ return new GnssCapabilities(flags, mMeasurementCorrectionsFlags, mPowerFlags);
+ }
}
/**
- * Returns {@code true} if GNSS chipset supports blocklisting satellites, {@code false}
+ * Returns a new GnssCapabilities object with gnss measurement corrections sub hal values set
+ * from the given flags.
+ *
+ * @hide
+ */
+ public GnssCapabilities withSubHalMeasurementCorrectionsFlags(
+ @SubHalMeasurementCorrectionsCapabilityFlags int flags) {
+ if (mMeasurementCorrectionsFlags == flags) {
+ return this;
+ } else {
+ return new GnssCapabilities(mTopFlags, flags, mPowerFlags);
+ }
+ }
+
+ /**
+ * Returns a new GnssCapabilities object with gnss measurement corrections sub hal values set
+ * from the given flags.
+ *
+ * @hide
+ */
+ public GnssCapabilities withSubHalPowerFlags(@SubHalPowerCapabilityFlags int flags) {
+ if (mPowerFlags == flags) {
+ return this;
+ } else {
+ return new GnssCapabilities(mTopFlags, mMeasurementCorrectionsFlags, flags);
+ }
+ }
+
+ /**
+ * Returns {@code true} if GNSS chipset supports scheduling, {@code false} otherwise.
+ *
+ * @hide
+ */
+ public boolean hasScheduling() {
+ return (mTopFlags & TOP_HAL_CAPABILITY_SCHEDULING) != 0;
+ }
+
+ /**
+ * Returns {@code true} if GNSS chipset supports Mobile Station Based assistance, {@code false}
* otherwise.
*
* @hide
*/
- @SystemApi
- public boolean hasSatelliteBlocklist() {
- return hasCapability(SATELLITE_BLOCKLIST);
+ public boolean hasMsb() {
+ return (mTopFlags & TOP_HAL_CAPABILITY_MSB) != 0;
+ }
+
+ /**
+ * Returns {@code true} if GNSS chipset supports Mobile Station Assisted assitance,
+ * {@code false} otherwise.
+ *
+ * @hide
+ */
+ public boolean hasMsa() {
+ return (mTopFlags & TOP_HAL_CAPABILITY_MSA) != 0;
+ }
+
+ /**
+ * Returns {@code true} if GNSS chipset supports single shot locating, {@code false} otherwise.
+ *
+ * @hide
+ */
+ public boolean hasSingleShot() {
+ return (mTopFlags & TOP_HAL_CAPABILITY_SINGLE_SHOT) != 0;
+ }
+
+ /**
+ * Returns {@code true} if GNSS chipset supports on demand time, {@code false} otherwise.
+ *
+ * @hide
+ */
+ public boolean hasOnDemandTime() {
+ return (mTopFlags & TOP_HAL_CAPABILITY_ON_DEMAND_TIME) != 0;
}
/**
@@ -140,27 +226,71 @@
*/
@SystemApi
public boolean hasGeofencing() {
- return hasCapability(GEOFENCING);
+ return (mTopFlags & TOP_HAL_CAPABILITY_GEOFENCING) != 0;
}
/**
* Returns {@code true} if GNSS chipset supports measurements, {@code false} otherwise.
*
- * @hide
+ * @see LocationManager#registerGnssMeasurementsCallback(Executor, GnssMeasurementsEvent.Callback)
*/
- @SystemApi
public boolean hasMeasurements() {
- return hasCapability(MEASUREMENTS);
+ return (mTopFlags & TOP_HAL_CAPABILITY_MEASUREMENTS) != 0;
}
/**
* Returns {@code true} if GNSS chipset supports navigation messages, {@code false} otherwise.
*
+ * @deprecated Use {@link #hasNavigationMessages()} instead.
+ *
+ * @hide
+ */
+ @Deprecated
+ @SystemApi
+ public boolean hasNavMessages() {
+ return hasNavigationMessages();
+ }
+
+ /**
+ * Returns {@code true} if GNSS chipset supports navigation messages, {@code false} otherwise.
+ *
+ * @see LocationManager#registerGnssNavigationMessageCallback(Executor, GnssNavigationMessage.Callback)
+ */
+ public boolean hasNavigationMessages() {
+ return (mTopFlags & TOP_HAL_CAPABILITY_NAV_MESSAGES) != 0;
+ }
+
+ /**
+ * Returns {@code true} if GNSS chipset supports low power mode, {@code false} otherwise.
+ *
* @hide
*/
@SystemApi
- public boolean hasNavMessages() {
- return hasCapability(NAV_MESSAGES);
+ public boolean hasLowPowerMode() {
+ return (mTopFlags & TOP_HAL_CAPABILITY_LOW_POWER_MODE) != 0;
+ }
+
+ /**
+ * Returns {@code true} if GNSS chipset supports satellite blocklists, {@code false} otherwise.
+ *
+ * @deprecated Use {@link #hasSatelliteBlocklist} instead.
+ *
+ * @hide
+ */
+ @SystemApi
+ @Deprecated
+ public boolean hasSatelliteBlacklist() {
+ return (mTopFlags & TOP_HAL_CAPABILITY_SATELLITE_BLOCKLIST) != 0;
+ }
+
+ /**
+ * Returns {@code true} if GNSS chipset supports satellite blocklists, {@code false} otherwise.
+ *
+ * @hide
+ */
+ @SystemApi
+ public boolean hasSatelliteBlocklist() {
+ return (mTopFlags & TOP_HAL_CAPABILITY_SATELLITE_BLOCKLIST) != 0;
}
/**
@@ -171,7 +301,26 @@
*/
@SystemApi
public boolean hasMeasurementCorrections() {
- return hasCapability(MEASUREMENT_CORRECTIONS);
+ return (mTopFlags & TOP_HAL_CAPABILITY_MEASUREMENT_CORRECTIONS) != 0;
+ }
+
+ /**
+ * Returns {@code true} if GNSS chipset supports antenna info, {@code false} otherwise.
+ *
+ * @deprecated Use {@link #hasAntennaInfo()} instead.
+ */
+ @Deprecated
+ public boolean hasGnssAntennaInfo() {
+ return hasAntennaInfo();
+ }
+
+ /**
+ * Returns {@code true} if GNSS chipset supports antenna info, {@code false} otherwise.
+ *
+ * @see LocationManager#registerAntennaInfoListener(Executor, GnssAntennaInfo.Listener)
+ */
+ public boolean hasAntennaInfo() {
+ return (mTopFlags & TOP_HAL_CAPABILITY_ANTENNA_INFO) != 0;
}
/**
@@ -182,7 +331,8 @@
*/
@SystemApi
public boolean hasMeasurementCorrectionsLosSats() {
- return hasCapability(MEASUREMENT_CORRECTIONS_LOS_SATS);
+ return (mMeasurementCorrectionsFlags & SUB_HAL_MEASUREMENT_CORRECTIONS_CAPABILITY_LOS_SATS)
+ != 0;
}
/**
@@ -193,28 +343,468 @@
*/
@SystemApi
public boolean hasMeasurementCorrectionsExcessPathLength() {
- return hasCapability(MEASUREMENT_CORRECTIONS_EXCESS_PATH_LENGTH);
+ return (mMeasurementCorrectionsFlags
+ & SUB_HAL_MEASUREMENT_CORRECTIONS_CAPABILITY_EXCESS_PATH_LENGTH) != 0;
}
/**
- * Returns {@code true} if GNSS chipset supports reflecting planes measurement corrections,
+ * Returns {@code true} if GNSS chipset supports reflecting plane measurement corrections,
* {@code false} otherwise.
*
+ * @deprecated Use {@link #hasMeasurementCorrectionsReflectingPlane()} instead.
+ *
* @hide
*/
@SystemApi
public boolean hasMeasurementCorrectionsReflectingPane() {
- return hasCapability(MEASUREMENT_CORRECTIONS_REFLECTING_PLANE);
+ return hasMeasurementCorrectionsReflectingPlane();
}
/**
- * Returns {@code true} if GNSS chipset supports antenna info, {@code false} otherwise.
+ * Returns {@code true} if GNSS chipset supports reflecting plane measurement corrections,
+ * {@code false} otherwise.
+ *
+ * @hide
*/
- public boolean hasGnssAntennaInfo() {
- return hasCapability(ANTENNA_INFO);
+ @SystemApi
+ public boolean hasMeasurementCorrectionsReflectingPlane() {
+ return (mMeasurementCorrectionsFlags
+ & SUB_HAL_MEASUREMENT_CORRECTIONS_CAPABILITY_REFLECTING_PLANE) != 0;
}
- private boolean hasCapability(long capability) {
- return (mGnssCapabilities & capability) == capability;
+ /**
+ * Returns {@code true} if GNSS chipset supports measuring power totals, {@code false}
+ * otherwise.
+ *
+ * @hide
+ */
+ public boolean hasPowerTotal() {
+ return (mPowerFlags & SUB_HAL_POWER_CAPABILITY_TOTAL) != 0;
+ }
+
+ /**
+ * Returns {@code true} if GNSS chipset supports measuring single-band tracking power,
+ * {@code false} otherwise.
+ *
+ * @hide
+ */
+ public boolean hasPowerSinglebandTracking() {
+ return (mPowerFlags & SUB_HAL_POWER_CAPABILITY_SINGLEBAND_TRACKING) != 0;
+ }
+
+ /**
+ * Returns {@code true} if GNSS chipset supports measuring multi-band tracking power,
+ * {@code false} otherwise.
+ *
+ * @hide
+ */
+ public boolean hasPowerMultibandTracking() {
+ return (mPowerFlags & SUB_HAL_POWER_CAPABILITY_MULTIBAND_TRACKING) != 0;
+ }
+
+ /**
+ * Returns {@code true} if GNSS chipset supports measuring single-band acquisition power,
+ * {@code false} otherwise.
+ *
+ * @hide
+ */
+ public boolean hasPowerSinglebandAcquisition() {
+ return (mPowerFlags & SUB_HAL_POWER_CAPABILITY_SINGLEBAND_ACQUISITION) != 0;
+ }
+
+ /**
+ * Returns {@code true} if GNSS chipset supports measuring multi-band acquisition power,
+ * {@code false} otherwise.
+ *
+ * @hide
+ */
+ public boolean hasPowerMultibandAcquisition() {
+ return (mPowerFlags & SUB_HAL_POWER_CAPABILITY_MULTIBAND_ACQUISITION) != 0;
+ }
+
+ /**
+ * Returns {@code true} if GNSS chipset supports measuring OEM defined mode power, {@code false}
+ * otherwise.
+ *
+ * @hide
+ */
+ public boolean hasPowerOtherModes() {
+ return (mPowerFlags & SUB_HAL_POWER_CAPABILITY_OTHER_MODES) != 0;
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (this == o) {
+ return true;
+ }
+ if (!(o instanceof GnssCapabilities)) {
+ return false;
+ }
+
+ GnssCapabilities that = (GnssCapabilities) o;
+ return mTopFlags == that.mTopFlags
+ && mMeasurementCorrectionsFlags == that.mMeasurementCorrectionsFlags
+ && mPowerFlags == that.mPowerFlags;
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(mTopFlags, mMeasurementCorrectionsFlags, mPowerFlags);
+ }
+
+ public static final @NonNull Creator<GnssCapabilities> CREATOR =
+ new Creator<GnssCapabilities>() {
+ @Override
+ public GnssCapabilities createFromParcel(Parcel in) {
+ return new GnssCapabilities(in.readInt(), in.readInt(), in.readInt());
+ }
+
+ @Override
+ public GnssCapabilities[] newArray(int size) {
+ return new GnssCapabilities[size];
+ }
+ };
+
+ @Override
+ public int describeContents() {
+ return 0;
+ }
+
+ @Override
+ public void writeToParcel(@NonNull Parcel parcel, int flags) {
+ parcel.writeInt(mTopFlags);
+ parcel.writeInt(mMeasurementCorrectionsFlags);
+ parcel.writeInt(mPowerFlags);
+ }
+
+ @Override
+ public String toString() {
+ StringBuilder builder = new StringBuilder();
+ builder.append("[");
+ if (hasScheduling()) {
+ builder.append("SCHEDULING ");
+ }
+ if (hasMsb()) {
+ builder.append("MSB ");
+ }
+ if (hasMsa()) {
+ builder.append("MSA ");
+ }
+ if (hasSingleShot()) {
+ builder.append("SINGLE_SHOT ");
+ }
+ if (hasOnDemandTime()) {
+ builder.append("ON_DEMAND_TIME ");
+ }
+ if (hasGeofencing()) {
+ builder.append("GEOFENCING ");
+ }
+ if (hasMeasurementCorrections()) {
+ builder.append("MEASUREMENTS ");
+ }
+ if (hasNavigationMessages()) {
+ builder.append("NAVIGATION_MESSAGES ");
+ }
+ if (hasLowPowerMode()) {
+ builder.append("LOW_POWER_MODE ");
+ }
+ if (hasSatelliteBlocklist()) {
+ builder.append("SATELLITE_BLOCKLIST ");
+ }
+ if (hasMeasurementCorrections()) {
+ builder.append("MEASUREMENT_CORRECTIONS ");
+ }
+ if (hasAntennaInfo()) {
+ builder.append("ANTENNA_INFO ");
+ }
+ if (hasMeasurementCorrectionsLosSats()) {
+ builder.append("LOS_SATS ");
+ }
+ if (hasMeasurementCorrectionsExcessPathLength()) {
+ builder.append("EXCESS_PATH_LENGTH ");
+ }
+ if (hasMeasurementCorrectionsReflectingPlane()) {
+ builder.append("REFLECTING_PLANE ");
+ }
+ if (hasPowerTotal()) {
+ builder.append("TOTAL_POWER ");
+ }
+ if (hasPowerSinglebandTracking()) {
+ builder.append("SINGLEBAND_TRACKING_POWER ");
+ }
+ if (hasPowerMultibandTracking()) {
+ builder.append("MULTIBAND_TRACKING_POWER ");
+ }
+ if (hasPowerSinglebandAcquisition()) {
+ builder.append("SINGLEBAND_ACQUISITION_POWER ");
+ }
+ if (hasPowerMultibandAcquisition()) {
+ builder.append("MULTIBAND_ACQUISITION_POWER ");
+ }
+ if (hasPowerOtherModes()) {
+ builder.append("OTHER_MODES_POWER ");
+ }
+ if (builder.length() > 1) {
+ builder.setLength(builder.length() - 1);
+ } else {
+ builder.append("NONE");
+ }
+ builder.append("]");
+ return builder.toString();
+ }
+
+ /**
+ * Builder for GnssCapabilities.
+ */
+ public static final class Builder {
+
+ private @TopHalCapabilityFlags int mTopFlags;
+ private @SubHalMeasurementCorrectionsCapabilityFlags int mMeasurementCorrectionsFlags;
+ private @SubHalPowerCapabilityFlags int mPowerFlags;
+
+ public Builder() {
+ mTopFlags = 0;
+ mMeasurementCorrectionsFlags = 0;
+ mPowerFlags = 0;
+ }
+
+ public Builder(@NonNull GnssCapabilities capabilities) {
+ mTopFlags = capabilities.mTopFlags;
+ mMeasurementCorrectionsFlags = capabilities.mMeasurementCorrectionsFlags;
+ mPowerFlags = capabilities.mPowerFlags;
+ }
+
+ /**
+ * Sets scheduling capability.
+ *
+ * @hide
+ */
+ public @NonNull Builder setHasScheduling(boolean capable) {
+ mTopFlags = setFlag(mTopFlags, TOP_HAL_CAPABILITY_SCHEDULING, capable);
+ return this;
+ }
+
+ /**
+ * Sets Mobile Station Based capability.
+ *
+ * @hide
+ */
+ public @NonNull Builder setHasMsb(boolean capable) {
+ mTopFlags = setFlag(mTopFlags, TOP_HAL_CAPABILITY_MSB, capable);
+ return this;
+ }
+
+ /**
+ * Sets Mobile Station Assisted capability.
+ *
+ * @hide
+ */
+ public @NonNull Builder setHasMsa(boolean capable) {
+ mTopFlags = setFlag(mTopFlags, TOP_HAL_CAPABILITY_MSA, capable);
+ return this;
+ }
+
+ /**
+ * Sets single shot locating capability.
+ *
+ * @hide
+ */
+ public @NonNull Builder setHasSingleShot(boolean capable) {
+ mTopFlags = setFlag(mTopFlags, TOP_HAL_CAPABILITY_SINGLE_SHOT, capable);
+ return this;
+ }
+
+ /**
+ * Sets on demand time capability.
+ *
+ * @hide
+ */
+ public @NonNull Builder setHasOnDemandTime(boolean capable) {
+ mTopFlags = setFlag(mTopFlags, TOP_HAL_CAPABILITY_ON_DEMAND_TIME, capable);
+ return this;
+ }
+
+ /**
+ * Sets geofencing capability.
+ *
+ * @hide
+ */
+ @SystemApi
+ public @NonNull Builder setHasGeofencing(boolean capable) {
+ mTopFlags = setFlag(mTopFlags, TOP_HAL_CAPABILITY_GEOFENCING, capable);
+ return this;
+ }
+
+ /**
+ * Sets measurements capability.
+ */
+ public @NonNull Builder setHasMeasurements(boolean capable) {
+ mTopFlags = setFlag(mTopFlags, TOP_HAL_CAPABILITY_MEASUREMENTS, capable);
+ return this;
+ }
+
+ /**
+ * Sets navigation messages capability.
+ */
+ public @NonNull Builder setHasNavigationMessages(boolean capable) {
+ mTopFlags = setFlag(mTopFlags, TOP_HAL_CAPABILITY_NAV_MESSAGES, capable);
+ return this;
+ }
+
+ /**
+ * Sets low power mode capability.
+ *
+ * @hide
+ */
+ @SystemApi
+ public @NonNull Builder setHasLowPowerMode(boolean capable) {
+ mTopFlags = setFlag(mTopFlags, TOP_HAL_CAPABILITY_LOW_POWER_MODE, capable);
+ return this;
+ }
+
+ /**
+ * Sets satellite blocklist capability.
+ *
+ * @hide
+ */
+ @SystemApi
+ public @NonNull Builder setHasSatelliteBlocklist(boolean capable) {
+ mTopFlags = setFlag(mTopFlags, TOP_HAL_CAPABILITY_SATELLITE_BLOCKLIST, capable);
+ return this;
+ }
+
+ /**
+ * Sets measurement corrections capability.
+ *
+ * @hide
+ */
+ @SystemApi
+ public @NonNull Builder setHasMeasurementCorrections(boolean capable) {
+ mTopFlags = setFlag(mTopFlags, TOP_HAL_CAPABILITY_MEASUREMENT_CORRECTIONS, capable);
+ return this;
+ }
+
+ /**
+ * Sets antenna info capability.
+ */
+ public @NonNull Builder setHasAntennaInfo(boolean capable) {
+ mTopFlags = setFlag(mTopFlags, TOP_HAL_CAPABILITY_ANTENNA_INFO, capable);
+ return this;
+ }
+
+ /**
+ * Sets measurement corrections line-of-sight satellites capabilitity.
+ *
+ * @hide
+ */
+ @SystemApi
+ public @NonNull Builder setHasMeasurementCorrectionsLosSats(boolean capable) {
+ mMeasurementCorrectionsFlags = setFlag(mMeasurementCorrectionsFlags,
+ SUB_HAL_MEASUREMENT_CORRECTIONS_CAPABILITY_LOS_SATS, capable);
+ return this;
+ }
+
+ /**
+ * Sets measurement corrections excess path length capabilitity.
+ *
+ * @hide
+ */
+ @SystemApi
+ public @NonNull Builder setHasMeasurementCorrectionsExcessPathLength(boolean capable) {
+ mMeasurementCorrectionsFlags = setFlag(mMeasurementCorrectionsFlags,
+ SUB_HAL_MEASUREMENT_CORRECTIONS_CAPABILITY_EXCESS_PATH_LENGTH, capable);
+ return this;
+ }
+
+ /**
+ * Sets measurement corrections reflecting plane capabilitity.
+ *
+ * @hide
+ */
+ @SystemApi
+ public @NonNull Builder setHasMeasurementCorrectionsReflectingPlane(boolean capable) {
+ mMeasurementCorrectionsFlags = setFlag(mMeasurementCorrectionsFlags,
+ SUB_HAL_MEASUREMENT_CORRECTIONS_CAPABILITY_REFLECTING_PLANE, capable);
+ return this;
+ }
+
+ /**
+ * Sets power totals capabilitity.
+ *
+ * @hide
+ */
+ public @NonNull Builder setHasPowerTotal(boolean capable) {
+ mPowerFlags = setFlag(mPowerFlags, SUB_HAL_POWER_CAPABILITY_TOTAL, capable);
+ return this;
+ }
+
+ /**
+ * Sets power single-band tracking capabilitity.
+ *
+ * @hide
+ */
+ public @NonNull Builder setHasPowerSinglebandTracking(boolean capable) {
+ mPowerFlags = setFlag(mPowerFlags, SUB_HAL_POWER_CAPABILITY_SINGLEBAND_TRACKING,
+ capable);
+ return this;
+ }
+
+ /**
+ * Sets power multi-band tracking capabilitity.
+ *
+ * @hide
+ */
+ public @NonNull Builder setHasPowerMultibandTracking(boolean capable) {
+ mPowerFlags = setFlag(mPowerFlags, SUB_HAL_POWER_CAPABILITY_MULTIBAND_TRACKING,
+ capable);
+ return this;
+ }
+
+ /**
+ * Sets power single-band acquisition capabilitity.
+ *
+ * @hide
+ */
+ public @NonNull Builder setHasPowerSinglebandAcquisition(boolean capable) {
+ mPowerFlags = setFlag(mPowerFlags, SUB_HAL_POWER_CAPABILITY_SINGLEBAND_ACQUISITION,
+ capable);
+ return this;
+ }
+
+ /**
+ * Sets power multi-band acquisition capabilitity.
+ *
+ * @hide
+ */
+ public @NonNull Builder setHasPowerMultibandAcquisition(boolean capable) {
+ mPowerFlags = setFlag(mPowerFlags, SUB_HAL_POWER_CAPABILITY_MULTIBAND_ACQUISITION,
+ capable);
+ return this;
+ }
+
+ /**
+ * Sets power other modes capabilitity.
+ *
+ * @hide
+ */
+ public @NonNull Builder setHasPowerOtherModes(boolean capable) {
+ mPowerFlags = setFlag(mPowerFlags, SUB_HAL_POWER_CAPABILITY_OTHER_MODES, capable);
+ return this;
+ }
+
+ /**
+ * Builds a new GnssCapabilities.
+ */
+ public @NonNull GnssCapabilities build() {
+ return new GnssCapabilities(mTopFlags, mMeasurementCorrectionsFlags, mPowerFlags);
+ }
+
+ private static int setFlag(int value, int flag, boolean set) {
+ if (set) {
+ return value | flag;
+ } else {
+ return value & ~flag;
+ }
+ }
}
}
diff --git a/location/java/com/android/internal/location/timezone/LocationTimeZoneEvent.aidl b/location/java/android/location/IGnssNmeaListener.aidl
similarity index 81%
copy from location/java/com/android/internal/location/timezone/LocationTimeZoneEvent.aidl
copy to location/java/android/location/IGnssNmeaListener.aidl
index 199e067..c67cc89 100644
--- a/location/java/com/android/internal/location/timezone/LocationTimeZoneEvent.aidl
+++ b/location/java/android/location/IGnssNmeaListener.aidl
@@ -14,6 +14,12 @@
* limitations under the License.
*/
-package com.android.internal.location.timezone;
+package android.location;
-parcelable LocationTimeZoneEvent;
+/**
+ * {@hide}
+ */
+oneway interface IGnssNmeaListener
+{
+ void onNmeaReceived(long timestamp, String nmea);
+}
\ No newline at end of file
diff --git a/location/java/android/location/IGnssStatusListener.aidl b/location/java/android/location/IGnssStatusListener.aidl
index 57b1268..c25046e 100644
--- a/location/java/android/location/IGnssStatusListener.aidl
+++ b/location/java/android/location/IGnssStatusListener.aidl
@@ -27,5 +27,4 @@
void onGnssStopped();
void onFirstFix(int ttff);
void onSvStatusChanged(in GnssStatus gnssStatus);
- void onNmeaReceived(long timestamp, String nmea);
}
diff --git a/location/java/android/location/ILocationManager.aidl b/location/java/android/location/ILocationManager.aidl
index a666eb4..621fe1b 100644
--- a/location/java/android/location/ILocationManager.aidl
+++ b/location/java/android/location/ILocationManager.aidl
@@ -21,6 +21,7 @@
import android.location.Criteria;
import android.location.GeocoderParams;
import android.location.Geofence;
+import android.location.GnssCapabilities;
import android.location.GnssMeasurementCorrections;
import android.location.GnssMeasurementRequest;
import android.location.IGeocodeListener;
@@ -28,17 +29,17 @@
import android.location.IGnssMeasurementsListener;
import android.location.IGnssStatusListener;
import android.location.IGnssNavigationMessageListener;
+import android.location.IGnssNmeaListener;
import android.location.ILocationCallback;
import android.location.ILocationListener;
import android.location.LastLocationRequest;
import android.location.Location;
import android.location.LocationRequest;
import android.location.LocationTime;
+import android.location.ProviderProperties;
import android.os.Bundle;
import android.os.ICancellationSignal;
-import com.android.internal.location.ProviderProperties;
-
/**
* System private API for talking with the location service.
*
@@ -71,13 +72,16 @@
double upperRightLatitude, double upperRightLongitude, int maxResults,
in GeocoderParams params, in IGeocodeListener listener);
- long getGnssCapabilities();
+ GnssCapabilities getGnssCapabilities();
int getGnssYearOfHardware();
String getGnssHardwareModelName();
void registerGnssStatusCallback(in IGnssStatusListener callback, String packageName, String attributionTag);
void unregisterGnssStatusCallback(in IGnssStatusListener callback);
+ void registerGnssNmeaCallback(in IGnssNmeaListener callback, String packageName, String attributionTag);
+ void unregisterGnssNmeaCallback(in IGnssNmeaListener callback);
+
void addGnssMeasurementsListener(in GnssMeasurementRequest request, in IGnssMeasurementsListener listener, String packageName, String attributionTag);
void removeGnssMeasurementsListener(in IGnssMeasurementsListener listener);
void injectGnssMeasurementCorrections(in GnssMeasurementCorrections corrections);
@@ -93,6 +97,7 @@
void flushGnssBatch();
void stopGnssBatch();
+ boolean hasProvider(String provider);
List<String> getAllProviders();
List<String> getProviders(in Criteria criteria, boolean enabledOnly);
String getBestProvider(in Criteria criteria, boolean enabledOnly);
diff --git a/location/java/android/location/LocationManager.java b/location/java/android/location/LocationManager.java
index 6026862..00381a6 100644
--- a/location/java/android/location/LocationManager.java
+++ b/location/java/android/location/LocationManager.java
@@ -61,7 +61,6 @@
import com.android.internal.annotations.GuardedBy;
import com.android.internal.listeners.ListenerExecutor;
import com.android.internal.listeners.ListenerTransportMultiplexer;
-import com.android.internal.location.ProviderProperties;
import com.android.internal.util.Preconditions;
import java.lang.ref.WeakReference;
@@ -381,6 +380,8 @@
@GuardedBy("mLock")
@Nullable private GnssStatusTransportMultiplexer mGnssStatusTransportMultiplexer;
@GuardedBy("mLock")
+ @Nullable private GnssNmeaTransportMultiplexer mGnssNmeaTransportMultiplexer;
+ @GuardedBy("mLock")
@Nullable private GnssMeasurementsTransportMultiplexer mGnssMeasurementsTransportMultiplexer;
@GuardedBy("mLock")
@Nullable private GnssNavigationTransportMultiplexer mGnssNavigationTransportMultiplexer;
@@ -404,6 +405,15 @@
}
}
+ private GnssNmeaTransportMultiplexer getGnssNmeaTransportMultiplexer() {
+ synchronized (mLock) {
+ if (mGnssNmeaTransportMultiplexer == null) {
+ mGnssNmeaTransportMultiplexer = new GnssNmeaTransportMultiplexer();
+ }
+ return mGnssNmeaTransportMultiplexer;
+ }
+ }
+
private GnssMeasurementsTransportMultiplexer getGnssMeasurementsTransportMultiplexer() {
synchronized (mLock) {
if (mGnssMeasurementsTransportMultiplexer == null) {
@@ -1616,6 +1626,25 @@
}
/**
+ * Returns true if the given location provider exists on this device, irrespective of whether
+ * it is currently enabled or not.
+ *
+ * @param provider a potential location provider
+ * @return true if the location provider exists, false otherwise
+ *
+ * @throws IllegalArgumentException if provider is null
+ */
+ public boolean hasProvider(@NonNull String provider) {
+ Preconditions.checkArgument(provider != null, "invalid null provider");
+
+ try {
+ return mService.hasProvider(provider);
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ }
+
+ /**
* Returns a list of the names of all available location providers. All providers are returned,
* including those that are currently disabled.
*
@@ -1703,7 +1732,12 @@
* @return location provider information, or null if provider does not exist
*
* @throws IllegalArgumentException if provider is null
+ *
+ * @deprecated This method has no way to indicate that a provider's properties are unknown, and
+ * so may return incorrect results on rare occasions. Use {@link #getProviderProperties(String)}
+ * instead.
*/
+ @Deprecated
public @Nullable LocationProvider getProvider(@NonNull String provider) {
Preconditions.checkArgument(provider != null, "invalid null provider");
@@ -1723,11 +1757,33 @@
}
try {
+
ProviderProperties properties = mService.getProviderProperties(provider);
- if (properties == null) {
- return null;
- }
return new LocationProvider(provider, properties);
+ } catch (IllegalArgumentException e) {
+ // provider does not exist
+ return null;
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ }
+
+ /**
+ * Returns the properties of the given provider, or null if the properties are currently
+ * unknown. Provider properties may change over time, although this is discouraged, and should
+ * be rare. The most common transition is when provider properties go from being unknown to
+ * known, which is most common near boot time.
+ *
+ * @param provider a provider listed by {@link #getAllProviders()}
+ * @return location provider properties, or null if properties are currently unknown
+ *
+ * @throws IllegalArgumentException if provider is null or does not exist
+ */
+ public @Nullable ProviderProperties getProviderProperties(@NonNull String provider) {
+ Preconditions.checkArgument(provider != null, "invalid null provider");
+
+ try {
+ return mService.getProviderProperties(provider);
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
@@ -1826,12 +1882,14 @@
public void addTestProvider(
@NonNull String provider, boolean requiresNetwork, boolean requiresSatellite,
boolean requiresCell, boolean hasMonetaryCost, boolean supportsAltitude,
- boolean supportsSpeed, boolean supportsBearing, int powerRequirement, int accuracy) {
+ boolean supportsSpeed, boolean supportsBearing,
+ @ProviderProperties.PowerUsage int powerUsage,
+ @ProviderProperties.Accuracy int accuracy) {
Preconditions.checkArgument(provider != null, "invalid null provider");
ProviderProperties properties = new ProviderProperties(requiresNetwork,
requiresSatellite, requiresCell, hasMonetaryCost, supportsAltitude, supportsSpeed,
- supportsBearing, powerRequirement, accuracy);
+ supportsBearing, powerUsage, accuracy);
try {
mService.addTestProvider(provider, properties, mContext.getOpPackageName(),
mContext.getFeatureId());
@@ -2045,20 +2103,15 @@
*/
public @NonNull GnssCapabilities getGnssCapabilities() {
try {
- long gnssCapabilities = mService.getGnssCapabilities();
- if (gnssCapabilities == GnssCapabilities.INVALID_CAPABILITIES) {
- gnssCapabilities = 0L;
- }
- return GnssCapabilities.of(gnssCapabilities);
+ return mService.getGnssCapabilities();
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
}
/**
- * Returns the model year of the GNSS hardware and software build. More details, such as build
- * date, may be available in {@link #getGnssHardwareModelName()}. May return 0 if the model year
- * is less than 2016.
+ * Returns the model year of the GNSS hardware and software build, or 0 if the model year
+ * is before 2016.
*/
public int getGnssYearOfHardware() {
try {
@@ -2069,13 +2122,10 @@
}
/**
- * Returns the Model Name (including Vendor and Hardware/Software Version) of the GNSS hardware
- * driver.
+ * Returns the model name (including vendor and hardware/software version) of the GNSS hardware
+ * driver, or null if this information is not available.
*
- * <p> No device-specific serial number or ID is returned from this API.
- *
- * <p> Will return null when the GNSS hardware abstraction layer does not support providing
- * this value.
+ * <p>No device-specific serial number or ID is returned from this API.
*/
@Nullable
public String getGnssHardwareModelName() {
@@ -2170,8 +2220,11 @@
* Registers a GNSS status callback. This method must be called from a {@link Looper} thread,
* and callbacks will occur on that looper.
*
- * @param callback GNSS status callback object to register
- * @return true if the listener was successfully added
+ * <p>See {@link #registerGnssStatusCallback(Executor, GnssStatus.Callback)} for more detail on
+ * how this method works.
+ *
+ * @param callback the callback to register
+ * @return {@code true} always
*
* @throws SecurityException if the ACCESS_FINE_LOCATION permission is not present
*
@@ -2187,9 +2240,12 @@
/**
* Registers a GNSS status callback.
*
- * @param callback GNSS status callback object to register
- * @param handler a handler with a looper that the callback runs on
- * @return true if the listener was successfully added
+ * <p>See {@link #registerGnssStatusCallback(Executor, GnssStatus.Callback)} for more detail on
+ * how this method works.
+ *
+ * @param callback the callback to register
+ * @param handler the handler the callback runs on
+ * @return {@code true} always
*
* @throws IllegalArgumentException if callback is null
* @throws SecurityException if the ACCESS_FINE_LOCATION permission is not present
@@ -2205,11 +2261,12 @@
}
/**
- * Registers a GNSS status callback.
+ * Registers a GNSS status callback. GNSS status information will only be received while the
+ * {@link #GPS_PROVIDER} is enabled, and while the client app is in the foreground.
*
* @param executor the executor that the callback runs on
- * @param callback GNSS status callback object to register
- * @return true if the listener was successfully added
+ * @param callback the callback to register
+ * @return {@code true} always
*
* @throws IllegalArgumentException if executor is null
* @throws IllegalArgumentException if callback is null
@@ -2254,8 +2311,12 @@
/**
* Adds an NMEA listener.
*
- * @param listener a {@link OnNmeaMessageListener} object to register
- * @return true if the listener was successfully added
+ * <p>See {@link #addNmeaListener(Executor, OnNmeaMessageListener)} for more detail on how this
+ * method works.
+ *
+ * @param listener the listener to register
+ * @return {@code true} always
+ *
* @throws SecurityException if the ACCESS_FINE_LOCATION permission is not present
* @deprecated Use {@link #addNmeaListener(OnNmeaMessageListener, Handler)} or {@link
* #addNmeaListener(Executor, OnNmeaMessageListener)} instead.
@@ -2269,9 +2330,12 @@
/**
* Adds an NMEA listener.
*
- * @param listener a {@link OnNmeaMessageListener} object to register
- * @param handler a handler with the looper that the listener runs on.
- * @return true if the listener was successfully added
+ * <p>See {@link #addNmeaListener(Executor, OnNmeaMessageListener)} for more detail on how this
+ * method works.
+ *
+ * @param listener the listener to register
+ * @param handler the handler that the listener runs on
+ * @return {@code true} always
*
* @throws IllegalArgumentException if listener is null
* @throws SecurityException if the ACCESS_FINE_LOCATION permission is not present
@@ -2287,11 +2351,12 @@
}
/**
- * Adds an NMEA listener.
+ * Adds an NMEA listener. GNSS NMEA information will only be received while the
+ * {@link #GPS_PROVIDER} is enabled, and while the client app is in the foreground.
*
- * @param listener a {@link OnNmeaMessageListener} object to register
- * @param executor the {@link Executor} that the listener runs on.
- * @return true if the listener was successfully added
+ * @param listener the listener to register
+ * @param executor the executor that the listener runs on
+ * @return {@code true} always
*
* @throws IllegalArgumentException if executor is null
* @throws IllegalArgumentException if listener is null
@@ -2301,7 +2366,7 @@
public boolean addNmeaListener(
@NonNull @CallbackExecutor Executor executor,
@NonNull OnNmeaMessageListener listener) {
- getGnssStatusTransportMultiplexer().addListener(listener, executor);
+ getGnssNmeaTransportMultiplexer().addListener(listener, executor);
return true;
}
@@ -2311,7 +2376,7 @@
* @param listener a {@link OnNmeaMessageListener} object to remove
*/
public void removeNmeaListener(@NonNull OnNmeaMessageListener listener) {
- getGnssStatusTransportMultiplexer().removeListener(listener);
+ getGnssNmeaTransportMultiplexer().removeListener(listener);
}
/**
@@ -2339,10 +2404,14 @@
public void removeGpsMeasurementListener(GpsMeasurementsEvent.Listener listener) {}
/**
- * Registers a GPS Measurement callback which will run on a binder thread.
+ * Registers a GNSS measurements callback which will run on a binder thread.
*
- * @param callback a {@link GnssMeasurementsEvent.Callback} object to register.
- * @return {@code true} if the callback was added successfully, {@code false} otherwise.
+ * <p>See {@link #registerGnssMeasurementsCallback(Executor, GnssMeasurementsEvent.Callback)
+ * for more detail on how this method works.
+ *
+ * @param callback a {@link GnssMeasurementsEvent.Callback} object to register
+ * @return {@code true} always
+ *
* @deprecated Use {@link
* #registerGnssMeasurementsCallback(GnssMeasurementsEvent.Callback, Handler)} or {@link
* #registerGnssMeasurementsCallback(Executor, GnssMeasurementsEvent.Callback)} instead.
@@ -2355,11 +2424,14 @@
}
/**
- * Registers a GPS Measurement callback.
+ * Registers a GNSS measurements callback.
*
- * @param callback a {@link GnssMeasurementsEvent.Callback} object to register.
- * @param handler the handler that the callback runs on.
- * @return {@code true} if the callback was added successfully, {@code false} otherwise.
+ * <p>See {@link #registerGnssMeasurementsCallback(Executor, GnssMeasurementsEvent.Callback)
+ * for more detail on how this method works.
+ *
+ * @param callback a {@link GnssMeasurementsEvent.Callback} object to register
+ * @param handler the handler that the callback runs on
+ * @return {@code true} always
*
* @throws IllegalArgumentException if callback is null
* @throws SecurityException if the ACCESS_FINE_LOCATION permission is not present
@@ -2376,11 +2448,14 @@
}
/**
- * Registers a GPS Measurement callback.
+ * Registers a GNSS measurements callback. GNSS measurements information will only be received
+ * while the {@link #GPS_PROVIDER} is enabled, and while the client app is in the foreground.
*
- * @param callback a {@link GnssMeasurementsEvent.Callback} object to register.
- * @param executor the executor that the callback runs on.
- * @return {@code true} if the callback was added successfully, {@code false} otherwise.
+ * <p>Not all GNSS chipsets support measurements updates, see {@link #getGnssCapabilities()}.
+ *
+ * @param executor the executor that the callback runs on
+ * @param callback the callback to register
+ * @return {@code true} always
*
* @throws IllegalArgumentException if executor is null
* @throws IllegalArgumentException if callback is null
@@ -2397,12 +2472,11 @@
/**
* Registers a GNSS Measurement callback.
*
- * @param request extra parameters to pass to GNSS measurement provider. For example, if {@link
- * GnssRequest#isFullTracking()} is true, GNSS chipset switches off duty
- * cycling.
- * @param executor the executor that the callback runs on.
- * @param callback a {@link GnssMeasurementsEvent.Callback} object to register.
- * @return {@code true} if the callback was added successfully, {@code false} otherwise.
+ * @param request the gnss measurement request containgin measurement parameters
+ * @param executor the executor that the callback runs on
+ * @param callback the callack to register
+ * @return {@code true} always
+ *
* @throws IllegalArgumentException if request is null
* @throws IllegalArgumentException if executor is null
* @throws IllegalArgumentException if callback is null
@@ -2451,8 +2525,7 @@
/**
* Injects GNSS measurement corrections into the GNSS chipset.
*
- * @param measurementCorrections a {@link GnssMeasurementCorrections} object with the GNSS
- * measurement corrections to be injected into the GNSS chipset.
+ * @param measurementCorrections measurement corrections to be injected into the chipset
*
* @throws IllegalArgumentException if measurementCorrections is null
* @throws SecurityException if the ACCESS_FINE_LOCATION permission is not present
@@ -2481,12 +2554,14 @@
}
/**
- * Registers a Gnss Antenna Info listener. Only expect results if
- * {@link GnssCapabilities#hasGnssAntennaInfo()} shows that antenna info is supported.
+ * Registers a GNSS antenna info listener. GNSS antenna info updates will only be received while
+ * the {@link #GPS_PROVIDER} is enabled, and while the client app is in the foreground.
*
- * @param executor the executor that the listener runs on.
- * @param listener a {@link GnssAntennaInfo.Listener} object to register.
- * @return {@code true} if the listener was added successfully, {@code false} otherwise.
+ * <p>Not all GNSS chipsets support antenna info updates, see {@link #getGnssCapabilities()}.
+ *
+ * @param executor the executor that the listener runs on
+ * @param listener the listener to register
+ * @return {@code true} always
*
* @throws IllegalArgumentException if executor is null
* @throws IllegalArgumentException if listener is null
@@ -2503,7 +2578,7 @@
/**
* Unregisters a GNSS Antenna Info listener.
*
- * @param listener a {@link GnssAntennaInfo.Listener} object to remove.
+ * @param listener a {@link GnssAntennaInfo.Listener} object to remove
*/
public void unregisterAntennaInfoListener(@NonNull GnssAntennaInfo.Listener listener) {
getGnssAntennaInfoTransportMultiplexer().removeListener(listener);
@@ -2534,10 +2609,15 @@
public void removeGpsNavigationMessageListener(GpsNavigationMessageEvent.Listener listener) {}
/**
- * Registers a GNSS Navigation Message callback which will run on a binder thread.
+ * Registers a GNSS navigation message callback which will run on a binder thread.
*
- * @param callback a {@link GnssNavigationMessage.Callback} object to register.
- * @return {@code true} if the callback was added successfully, {@code false} otherwise.
+ * <p>See
+ * {@link #registerGnssNavigationMessageCallback(Executor, GnssNavigationMessage.Callback)} for
+ * more detail on how this method works.
+ *
+ * @param callback the callback to register
+ * @return {@code true} always
+ *
* @deprecated Use {@link
* #registerGnssNavigationMessageCallback(GnssNavigationMessage.Callback, Handler)} or {@link
* #registerGnssNavigationMessageCallback(Executor, GnssNavigationMessage.Callback)} instead.
@@ -2549,11 +2629,15 @@
}
/**
- * Registers a GNSS Navigation Message callback.
+ * Registers a GNSS navigation message callback.
*
- * @param callback a {@link GnssNavigationMessage.Callback} object to register.
- * @param handler the handler that the callback runs on.
- * @return {@code true} if the callback was added successfully, {@code false} otherwise.
+ * <p>See
+ * {@link #registerGnssNavigationMessageCallback(Executor, GnssNavigationMessage.Callback)} for
+ * more detail on how this method works.
+ *
+ * @param callback the callback to register
+ * @param handler the handler that the callback runs on
+ * @return {@code true} always
*
* @throws IllegalArgumentException if callback is null
* @throws SecurityException if the ACCESS_FINE_LOCATION permission is not present
@@ -2569,11 +2653,15 @@
}
/**
- * Registers a GNSS Navigation Message callback.
+ * Registers a GNSS navigation message callback. GNSS navigation messages will only be received
+ * while the {@link #GPS_PROVIDER} is enabled, and while the client app is in the foreground.
*
- * @param callback a {@link GnssNavigationMessage.Callback} object to register.
- * @param executor the looper that the callback runs on.
- * @return {@code true} if the callback was added successfully, {@code false} otherwise.
+ * <p>Not all GNSS chipsets support navigation message updates, see
+ * {@link #getGnssCapabilities()}.
+ *
+ * @param executor the executor that the callback runs on
+ * @param callback the callback to register
+ * @return {@code true} always
*
* @throws IllegalArgumentException if executor is null
* @throws IllegalArgumentException if callback is null
@@ -2807,20 +2895,6 @@
}
}
- private static class NmeaAdapter extends GnssStatus.Callback implements OnNmeaMessageListener {
-
- private final OnNmeaMessageListener mListener;
-
- NmeaAdapter(OnNmeaMessageListener listener) {
- mListener = listener;
- }
-
- @Override
- public void onNmeaMessage(String message, long timestamp) {
- mListener.onNmeaMessage(message, timestamp);
- }
- }
-
private static class GpsAdapter extends GnssStatus.Callback {
private final GpsStatus.Listener mGpsListener;
@@ -2868,11 +2942,6 @@
return mTtff;
}
- public void addListener(@NonNull OnNmeaMessageListener listener,
- @NonNull Executor executor) {
- addListener(listener, null, new NmeaAdapter(listener), executor);
- }
-
public void addListener(@NonNull GpsStatus.Listener listener, @NonNull Executor executor) {
addListener(listener, null, new GpsAdapter(listener), executor);
}
@@ -2925,14 +2994,51 @@
mGnssStatus = gnssStatus;
deliverToListeners(callback -> callback.onSatelliteStatusChanged(gnssStatus));
}
+ }
+ }
+
+ private class GnssNmeaTransportMultiplexer extends
+ ListenerTransportMultiplexer<Void, OnNmeaMessageListener> {
+
+ private @Nullable IGnssNmeaListener mListenerTransport;
+
+ GnssNmeaTransportMultiplexer() {}
+
+ public void addListener(@NonNull OnNmeaMessageListener listener,
+ @NonNull Executor executor) {
+ addListener(listener, null, listener, executor);
+ }
+
+ @Override
+ protected void registerWithServer(Void ignored) throws RemoteException {
+ IGnssNmeaListener transport = mListenerTransport;
+ if (transport == null) {
+ transport = new GnssNmeaListener();
+ }
+
+ // if a remote exception is thrown the transport should not be set
+ mListenerTransport = null;
+ mService.registerGnssNmeaCallback(transport, mContext.getPackageName(),
+ mContext.getAttributionTag());
+ mListenerTransport = transport;
+ }
+
+ @Override
+ protected void unregisterWithServer() throws RemoteException {
+ if (mListenerTransport != null) {
+ IGnssNmeaListener transport = mListenerTransport;
+ mListenerTransport = null;
+ mService.unregisterGnssNmeaCallback(transport);
+ }
+ }
+
+ private class GnssNmeaListener extends IGnssNmeaListener.Stub {
+
+ GnssNmeaListener() {}
@Override
public void onNmeaReceived(long timestamp, String nmea) {
- deliverToListeners((callback) -> {
- if (callback instanceof NmeaAdapter) {
- ((NmeaAdapter) callback).onNmeaMessage(nmea, timestamp);
- }
- });
+ deliverToListeners(callback -> callback.onNmeaMessage(nmea, timestamp));
}
}
}
diff --git a/location/java/android/location/LocationProvider.java b/location/java/android/location/LocationProvider.java
index b950604..6d2bfed 100644
--- a/location/java/android/location/LocationProvider.java
+++ b/location/java/android/location/LocationProvider.java
@@ -16,23 +16,15 @@
package android.location;
-
-import com.android.internal.location.ProviderProperties;
+import android.annotation.Nullable;
/**
- * An abstract superclass for location providers. A location provider
- * provides periodic reports on the geographical location of the
- * device.
+ * Information about the properties of a location provider.
*
- * <p> Each provider has a set of criteria under which it may be used;
- * for example, some providers require GPS hardware and visibility to
- * a number of satellites; others require the use of the cellular
- * radio, or access to a specific carrier's network, or to the
- * internet. They may also have different battery consumption
- * characteristics or monetary costs to the user. The {@link
- * Criteria} class allows providers to be selected based on
- * user-specified criteria.
+ * @deprecated This class is incapable of representing unknown provider properties and may return
+ * incorrect results when the properties are unknown.
*/
+@Deprecated
public class LocationProvider {
/**
@@ -54,9 +46,9 @@
public static final int AVAILABLE = 2;
private final String mName;
- private final ProviderProperties mProperties;
+ private final @Nullable ProviderProperties mProperties;
- LocationProvider(String name, ProviderProperties properties) {
+ LocationProvider(String name, @Nullable ProviderProperties properties) {
mName = name;
mProperties = properties;
}
@@ -96,7 +88,7 @@
return false;
}
if (criteria.getPowerRequirement() != Criteria.NO_REQUIREMENT &&
- criteria.getPowerRequirement() < properties.getPowerRequirement()) {
+ criteria.getPowerRequirement() < properties.getPowerUsage()) {
return false;
}
if (criteria.isAltitudeRequired() && !properties.hasAltitudeSupport()) {
@@ -119,7 +111,11 @@
* data network (e.g., the Internet), false otherwise.
*/
public boolean requiresNetwork() {
- return mProperties.hasNetworkRequirement();
+ if (mProperties == null) {
+ return false;
+ } else {
+ return mProperties.hasNetworkRequirement();
+ }
}
/**
@@ -128,7 +124,11 @@
* otherwise.
*/
public boolean requiresSatellite() {
- return mProperties.hasSatelliteRequirement();
+ if (mProperties == null) {
+ return false;
+ } else {
+ return mProperties.hasSatelliteRequirement();
+ }
}
/**
@@ -137,7 +137,11 @@
* otherwise.
*/
public boolean requiresCell() {
- return mProperties.hasCellRequirement();
+ if (mProperties == null) {
+ return false;
+ } else {
+ return mProperties.hasCellRequirement();
+ }
}
/**
@@ -146,7 +150,11 @@
* each provider to give accurate information.
*/
public boolean hasMonetaryCost() {
- return mProperties.hasMonetaryCost();
+ if (mProperties == null) {
+ return false;
+ } else {
+ return mProperties.hasMonetaryCost();
+ }
}
/**
@@ -156,7 +164,11 @@
* should return true.
*/
public boolean supportsAltitude() {
- return mProperties.hasAltitudeSupport();
+ if (mProperties == null) {
+ return false;
+ } else {
+ return mProperties.hasAltitudeSupport();
+ }
}
/**
@@ -166,7 +178,11 @@
* should return true.
*/
public boolean supportsSpeed() {
- return mProperties.hasSpeedSupport();
+ if (mProperties == null) {
+ return false;
+ } else {
+ return mProperties.hasSpeedSupport();
+ }
}
/**
@@ -176,27 +192,39 @@
* should return true.
*/
public boolean supportsBearing() {
- return mProperties.hasBearingSupport();
+ if (mProperties == null) {
+ return false;
+ } else {
+ return mProperties.hasBearingSupport();
+ }
}
/**
* Returns the power requirement for this provider.
*
* @return the power requirement for this provider, as one of the
- * constants Criteria.POWER_REQUIREMENT_*.
+ * constants ProviderProperties.POWER_USAGE_*.
*/
public int getPowerRequirement() {
- return mProperties.getPowerRequirement();
+ if (mProperties == null) {
+ return ProviderProperties.POWER_USAGE_HIGH;
+ } else {
+ return mProperties.getPowerUsage();
+ }
}
/**
* Returns a constant describing horizontal accuracy of this provider.
* If the provider returns finer grain or exact location,
- * {@link Criteria#ACCURACY_FINE} is returned, otherwise if the
- * location is only approximate then {@link Criteria#ACCURACY_COARSE}
+ * {@link ProviderProperties#ACCURACY_FINE} is returned, otherwise if the
+ * location is only approximate then {@link ProviderProperties#ACCURACY_COARSE}
* is returned.
*/
public int getAccuracy() {
- return mProperties.getAccuracy();
+ if (mProperties == null) {
+ return ProviderProperties.ACCURACY_COARSE;
+ } else {
+ return mProperties.getAccuracy();
+ }
}
}
diff --git a/location/java/com/android/internal/location/ProviderProperties.aidl b/location/java/android/location/ProviderProperties.aidl
similarity index 94%
rename from location/java/com/android/internal/location/ProviderProperties.aidl
rename to location/java/android/location/ProviderProperties.aidl
index b901444..8b1d79f 100644
--- a/location/java/com/android/internal/location/ProviderProperties.aidl
+++ b/location/java/android/location/ProviderProperties.aidl
@@ -14,6 +14,6 @@
* limitations under the License.
*/
-package com.android.internal.location;
+package android.location;
parcelable ProviderProperties;
diff --git a/location/java/com/android/internal/location/ProviderProperties.java b/location/java/android/location/ProviderProperties.java
similarity index 75%
rename from location/java/com/android/internal/location/ProviderProperties.java
rename to location/java/android/location/ProviderProperties.java
index dbb61d2..8fa8c98 100644
--- a/location/java/com/android/internal/location/ProviderProperties.java
+++ b/location/java/android/location/ProviderProperties.java
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2012 The Android Open Source Project
+ * Copyright (C) 2020 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -14,10 +14,10 @@
* limitations under the License.
*/
-package com.android.internal.location;
+package android.location;
import android.annotation.IntDef;
-import android.location.Criteria;
+import android.annotation.NonNull;
import android.os.Parcel;
import android.os.Parcelable;
@@ -29,18 +29,43 @@
/**
* Location provider properties.
- * @hide
*/
public final class ProviderProperties implements Parcelable {
- /** @hide */
- @Retention(RetentionPolicy.SOURCE)
- @IntDef({Criteria.POWER_LOW, Criteria.POWER_MEDIUM, Criteria.POWER_HIGH})
- public @interface PowerRequirement {}
+ /**
+ * A constant indicating low power usage.
+ */
+ public static final int POWER_USAGE_LOW = 1;
+
+ /**
+ * A constant indicating a medium power usage.
+ */
+ public static final int POWER_USAGE_MEDIUM = 2;
+
+ /**
+ * A constant indicating high power usage.
+ */
+ public static final int POWER_USAGE_HIGH = 3;
/** @hide */
@Retention(RetentionPolicy.SOURCE)
- @IntDef({Criteria.ACCURACY_FINE, Criteria.ACCURACY_COARSE})
+ @IntDef(prefix = "POWER_USAGE_", value = {POWER_USAGE_LOW, POWER_USAGE_MEDIUM,
+ POWER_USAGE_HIGH})
+ public @interface PowerUsage {}
+
+ /**
+ * A constant indicating a finer location accuracy.
+ */
+ public static final int ACCURACY_FINE = 1;
+
+ /**
+ * A constant indicating a coarser location accuracy.
+ */
+ public static final int ACCURACY_COARSE = 2;
+
+ /** @hide */
+ @Retention(RetentionPolicy.SOURCE)
+ @IntDef(prefix = "ACCURACY_", value = {ACCURACY_FINE, ACCURACY_COARSE})
public @interface Accuracy {}
private final boolean mHasNetworkRequirement;
@@ -50,13 +75,16 @@
private final boolean mHasAltitudeSupport;
private final boolean mHasSpeedSupport;
private final boolean mHasBearingSupport;
- private final @PowerRequirement int mPowerRequirement;
+ private final @PowerUsage int mPowerUsage;
private final @Accuracy int mAccuracy;
+ /**
+ * @hide
+ */
public ProviderProperties(boolean hasNetworkRequirement, boolean hasSatelliteRequirement,
boolean hasCellRequirement, boolean hasMonetaryCost, boolean hasAltitudeSupport,
boolean hasSpeedSupport, boolean hasBearingSupport,
- @PowerRequirement int powerRequirement, @Accuracy int accuracy) {
+ @PowerUsage int powerUsage, @Accuracy int accuracy) {
mHasNetworkRequirement = hasNetworkRequirement;
mHasSatelliteRequirement = hasSatelliteRequirement;
mHasCellRequirement = hasCellRequirement;
@@ -64,10 +92,10 @@
mHasAltitudeSupport = hasAltitudeSupport;
mHasSpeedSupport = hasSpeedSupport;
mHasBearingSupport = hasBearingSupport;
- mPowerRequirement = Preconditions.checkArgumentInRange(powerRequirement, Criteria.POWER_LOW,
- Criteria.POWER_HIGH, "powerRequirement");
- mAccuracy = Preconditions.checkArgumentInRange(accuracy, Criteria.ACCURACY_FINE,
- Criteria.ACCURACY_COARSE, "accuracy");
+ mPowerUsage = Preconditions.checkArgumentInRange(powerUsage, POWER_USAGE_LOW,
+ POWER_USAGE_HIGH, "powerUsage");
+ mAccuracy = Preconditions.checkArgumentInRange(accuracy, ACCURACY_FINE,
+ ACCURACY_COARSE, "locationAccuracy");
}
/**
@@ -121,22 +149,22 @@
}
/**
- * Power requirement for this provider.
+ * Power usage for this provider.
*/
- public @PowerRequirement int getPowerRequirement() {
- return mPowerRequirement;
+ public @PowerUsage int getPowerUsage() {
+ return mPowerUsage;
}
/**
- * Constant describing the horizontal accuracy returned
- * by this provider.
+ * Rough location accuracy for this provider, primarily with respect to horizontal location
+ * accuracy.
*/
public @Accuracy int getAccuracy() {
return mAccuracy;
}
- public static final Parcelable.Creator<ProviderProperties> CREATOR =
- new Parcelable.Creator<ProviderProperties>() {
+ public static final @NonNull Creator<ProviderProperties> CREATOR =
+ new Creator<ProviderProperties>() {
@Override
public ProviderProperties createFromParcel(Parcel in) {
return new ProviderProperties(
@@ -147,7 +175,7 @@
/* hasAltitudeSupport= */ in.readBoolean(),
/* hasSpeedSupport= */ in.readBoolean(),
/* hasBearingSupport= */ in.readBoolean(),
- /* powerRequirement= */ in.readInt(),
+ /* powerUsage= */ in.readInt(),
/* accuracy= */ in.readInt());
}
@@ -163,7 +191,7 @@
}
@Override
- public void writeToParcel(Parcel parcel, int flags) {
+ public void writeToParcel(@NonNull Parcel parcel, int flags) {
parcel.writeBoolean(mHasNetworkRequirement);
parcel.writeBoolean(mHasSatelliteRequirement);
parcel.writeBoolean(mHasCellRequirement);
@@ -171,7 +199,7 @@
parcel.writeBoolean(mHasAltitudeSupport);
parcel.writeBoolean(mHasSpeedSupport);
parcel.writeBoolean(mHasBearingSupport);
- parcel.writeInt(mPowerRequirement);
+ parcel.writeInt(mPowerUsage);
parcel.writeInt(mAccuracy);
}
@@ -191,7 +219,7 @@
&& mHasAltitudeSupport == that.mHasAltitudeSupport
&& mHasSpeedSupport == that.mHasSpeedSupport
&& mHasBearingSupport == that.mHasBearingSupport
- && mPowerRequirement == that.mPowerRequirement
+ && mPowerUsage == that.mPowerUsage
&& mAccuracy == that.mAccuracy;
}
@@ -199,13 +227,13 @@
public int hashCode() {
return Objects.hash(mHasNetworkRequirement, mHasSatelliteRequirement, mHasCellRequirement,
mHasMonetaryCost, mHasAltitudeSupport, mHasSpeedSupport, mHasBearingSupport,
- mPowerRequirement, mAccuracy);
+ mPowerUsage, mAccuracy);
}
@Override
public String toString() {
StringBuilder b = new StringBuilder("ProviderProperties[");
- b.append("power=").append(powerToString(mPowerRequirement)).append(", ");
+ b.append("power=").append(powerToString(mPowerUsage)).append(", ");
b.append("accuracy=").append(accuracyToString(mAccuracy));
if (mHasNetworkRequirement || mHasSatelliteRequirement || mHasCellRequirement) {
b.append(", requires=");
@@ -226,42 +254,42 @@
if (mHasBearingSupport || mHasSpeedSupport || mHasAltitudeSupport) {
b.append(", supports=[");
if (mHasBearingSupport) {
- b.append("bearing, ");
+ b.append("bearing,");
}
if (mHasSpeedSupport) {
- b.append("speed, ");
+ b.append("speed,");
}
if (mHasAltitudeSupport) {
- b.append("altitude, ");
+ b.append("altitude,");
}
- b.setLength(b.length() - 2);
+ b.setLength(b.length() - 1);
b.append("]");
}
b.append("]");
return b.toString();
}
- private static String powerToString(@PowerRequirement int power) {
+ private static String powerToString(@PowerUsage int power) {
switch (power) {
- case Criteria.POWER_LOW:
+ case POWER_USAGE_LOW:
return "Low";
- case Criteria.POWER_MEDIUM:
+ case POWER_USAGE_MEDIUM:
return "Medium";
- case Criteria.POWER_HIGH:
+ case POWER_USAGE_HIGH:
return "High";
default:
- return "???";
+ throw new AssertionError();
}
}
private static String accuracyToString(@Accuracy int accuracy) {
switch (accuracy) {
- case Criteria.ACCURACY_COARSE:
+ case ACCURACY_COARSE:
return "Coarse";
- case Criteria.ACCURACY_FINE:
+ case ACCURACY_FINE:
return "Fine";
default:
- return "???";
+ throw new AssertionError();
}
}
}
diff --git a/location/java/com/android/internal/location/GpsNetInitiatedHandler.java b/location/java/com/android/internal/location/GpsNetInitiatedHandler.java
index 4a095c9..4ce9a320 100644
--- a/location/java/com/android/internal/location/GpsNetInitiatedHandler.java
+++ b/location/java/com/android/internal/location/GpsNetInitiatedHandler.java
@@ -50,9 +50,6 @@
private static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG);
- // NI verify activity for bringing up UI (not used yet)
- public static final String ACTION_NI_VERIFY = "android.intent.action.NETWORK_INITIATED_VERIFY";
-
// string constants for defining data fields in NI Intent
public static final String NI_INTENT_KEY_NOTIF_ID = "notif_id";
public static final String NI_INTENT_KEY_TITLE = "title";
diff --git a/location/java/com/android/internal/location/ILocationProviderManager.aidl b/location/java/com/android/internal/location/ILocationProviderManager.aidl
index a74538b..a5b22b2 100644
--- a/location/java/com/android/internal/location/ILocationProviderManager.aidl
+++ b/location/java/com/android/internal/location/ILocationProviderManager.aidl
@@ -17,17 +17,17 @@
package com.android.internal.location;
import android.location.LocationResult;
-
-import com.android.internal.location.ProviderProperties;
+import android.location.ProviderProperties;
/**
* Binder interface for manager of all location providers.
* @hide
*/
interface ILocationProviderManager {
- void onSetIdentity(@nullable String packageName, @nullable String attributionTag);
+ void onInitialize(boolean allowed, in ProviderProperties properties, @nullable String packageName, @nullable String attributionTag);
void onSetAllowed(boolean allowed);
void onSetProperties(in ProviderProperties properties);
+
void onReportLocation(in LocationResult locationResult);
void onFlushComplete();
}
diff --git a/location/java/com/android/internal/location/timezone/ILocationTimeZoneProvider.aidl b/location/java/com/android/internal/location/timezone/ILocationTimeZoneProvider.aidl
deleted file mode 100644
index 16aa848..0000000
--- a/location/java/com/android/internal/location/timezone/ILocationTimeZoneProvider.aidl
+++ /dev/null
@@ -1,33 +0,0 @@
-/*
- * Copyright (C) 2020 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.internal.location.timezone;
-
-import com.android.internal.location.timezone.ILocationTimeZoneProviderManager;
-import com.android.internal.location.timezone.LocationTimeZoneProviderRequest;
-
-/**
- * Binder interface for location time zone provider implementations. Do not implement this
- * directly, extend {@link com.android.location.timezone.provider.LocationTimeZoneProviderBase}
- * instead.
- * @hide
- */
-interface ILocationTimeZoneProvider {
-
- oneway void setLocationTimeZoneProviderManager(in ILocationTimeZoneProviderManager manager);
-
- oneway void setRequest(in LocationTimeZoneProviderRequest request);
-}
diff --git a/location/java/com/android/internal/location/timezone/LocationTimeZoneEvent.java b/location/java/com/android/internal/location/timezone/LocationTimeZoneEvent.java
deleted file mode 100644
index 31c27d1..0000000
--- a/location/java/com/android/internal/location/timezone/LocationTimeZoneEvent.java
+++ /dev/null
@@ -1,244 +0,0 @@
-/*
- * Copyright (C) 2020 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.internal.location.timezone;
-
-import android.annotation.IntDef;
-import android.annotation.NonNull;
-import android.annotation.Nullable;
-import android.os.Parcel;
-import android.os.Parcelable;
-
-import com.android.internal.util.Preconditions;
-
-import java.time.Duration;
-import java.util.ArrayList;
-import java.util.Collections;
-import java.util.List;
-import java.util.Objects;
-
-/**
- * An event containing location time zone information.
- *
- * @hide
- */
-public final class LocationTimeZoneEvent implements Parcelable {
-
- @IntDef({ EVENT_TYPE_UNKNOWN, EVENT_TYPE_PERMANENT_FAILURE, EVENT_TYPE_SUCCESS,
- EVENT_TYPE_UNCERTAIN })
- public @interface EventType {}
-
- /** Uninitialized value for {@link #mEventType} - must not be used for real events. */
- private static final int EVENT_TYPE_UNKNOWN = 0;
-
- /**
- * Indicates there was a permanent failure. This is not generally expected, and probably means a
- * required backend service has been turned down, or the client is unreasonably old.
- */
- public static final int EVENT_TYPE_PERMANENT_FAILURE = 1;
-
- /**
- * Indicates a successful geolocation time zone detection event. {@link #getTimeZoneIds()} will
- * be non-null but can legitimately be empty, e.g. for disputed areas, oceans.
- */
- public static final int EVENT_TYPE_SUCCESS = 2;
-
- /**
- * Indicates the time zone is not known because of an expected runtime state or error, e.g. when
- * the provider is unable to detect location, or there was a problem when resolving the location
- * to a time zone.
- */
- public static final int EVENT_TYPE_UNCERTAIN = 3;
-
- private static final int EVENT_TYPE_MAX = EVENT_TYPE_UNCERTAIN;
-
- @EventType
- private final int mEventType;
-
- @NonNull
- private final List<String> mTimeZoneIds;
-
- private final long mElapsedRealtimeMillis;
-
- private LocationTimeZoneEvent(@EventType int eventType, @NonNull List<String> timeZoneIds,
- long elapsedRealtimeMillis) {
- mEventType = checkValidEventType(eventType);
- mTimeZoneIds = immutableList(timeZoneIds);
-
- boolean emptyTimeZoneIdListExpected = eventType != EVENT_TYPE_SUCCESS;
- Preconditions.checkState(!emptyTimeZoneIdListExpected || timeZoneIds.isEmpty());
-
- mElapsedRealtimeMillis = elapsedRealtimeMillis;
- }
-
- /**
- * Returns the time of this fix, in elapsed real-time since system boot.
- *
- * <p>This value can be reliably compared to {@link
- * android.os.SystemClock#elapsedRealtime()}, to calculate the age of a fix and to compare
- * {@link LocationTimeZoneEvent} instances.
- *
- * @return elapsed real-time of fix, in milliseconds
- */
- public long getElapsedRealtimeMillis() {
- return mElapsedRealtimeMillis;
- }
-
- /**
- * Returns the event type.
- */
- @Nullable
- public @EventType int getEventType() {
- return mEventType;
- }
-
- /**
- * Gets the time zone IDs of this event. Contains zero or more IDs for a successful lookup.
- * The value is undefined for an unsuccessful lookup. See also {@link #getEventType()}.
- */
- @NonNull
- public List<String> getTimeZoneIds() {
- return mTimeZoneIds;
- }
-
- @Override
- public String toString() {
- return "LocationTimeZoneEvent{"
- + "mEventType=" + mEventType
- + ", mTimeZoneIds=" + mTimeZoneIds
- + ", mElapsedRealtimeMillis=" + mElapsedRealtimeMillis
- + "(" + Duration.ofMillis(mElapsedRealtimeMillis) + ")"
- + '}';
- }
-
- public static final @NonNull Parcelable.Creator<LocationTimeZoneEvent> CREATOR =
- new Parcelable.Creator<LocationTimeZoneEvent>() {
- @Override
- public LocationTimeZoneEvent createFromParcel(Parcel in) {
- int eventType = in.readInt();
- @SuppressWarnings("unchecked")
- ArrayList<String> timeZoneIds =
- (ArrayList<String>) in.readArrayList(null /* classLoader */);
- long elapsedRealtimeMillis = in.readLong();
- return new LocationTimeZoneEvent(eventType, timeZoneIds, elapsedRealtimeMillis);
- }
-
- @Override
- public LocationTimeZoneEvent[] newArray(int size) {
- return new LocationTimeZoneEvent[size];
- }
- };
-
- @Override
- public int describeContents() {
- return 0;
- }
-
- @Override
- public void writeToParcel(Parcel parcel, int flags) {
- parcel.writeInt(mEventType);
- parcel.writeList(mTimeZoneIds);
- parcel.writeLong(mElapsedRealtimeMillis);
- }
-
- @Override
- public boolean equals(Object o) {
- if (this == o) {
- return true;
- }
- if (o == null || getClass() != o.getClass()) {
- return false;
- }
- LocationTimeZoneEvent that = (LocationTimeZoneEvent) o;
- return mEventType == that.mEventType
- && mElapsedRealtimeMillis == that.mElapsedRealtimeMillis
- && mTimeZoneIds.equals(that.mTimeZoneIds);
- }
-
- @Override
- public int hashCode() {
- return Objects.hash(mEventType, mTimeZoneIds, mElapsedRealtimeMillis);
- }
-
- /** @hide */
- public static final class Builder {
-
- private @EventType int mEventType = EVENT_TYPE_UNKNOWN;
- private @NonNull List<String> mTimeZoneIds = Collections.emptyList();
- private long mElapsedRealtimeMillis;
-
- public Builder() {
- }
-
- /**
- * Sets the contents of this from the supplied instance.
- */
- public Builder(@NonNull LocationTimeZoneEvent ltz) {
- mEventType = ltz.mEventType;
- mTimeZoneIds = ltz.mTimeZoneIds;
- mElapsedRealtimeMillis = ltz.mElapsedRealtimeMillis;
- }
-
- /**
- * Set the time zone ID of this event.
- */
- public Builder setEventType(@EventType int eventType) {
- checkValidEventType(eventType);
- mEventType = eventType;
- return this;
- }
-
- /**
- * Sets the time zone IDs of this event.
- */
- public Builder setTimeZoneIds(@NonNull List<String> timeZoneIds) {
- mTimeZoneIds = Objects.requireNonNull(timeZoneIds);
- return this;
- }
-
- /**
- * Sets the time of this event, in elapsed real-time since system boot.
- */
- public Builder setElapsedRealtimeMillis(long time) {
- mElapsedRealtimeMillis = time;
- return this;
- }
-
- /**
- * Builds a {@link LocationTimeZoneEvent} instance.
- */
- public LocationTimeZoneEvent build() {
- return new LocationTimeZoneEvent(mEventType, mTimeZoneIds, mElapsedRealtimeMillis);
- }
- }
-
- private static int checkValidEventType(int eventType) {
- if (eventType <= EVENT_TYPE_UNKNOWN || eventType > EVENT_TYPE_MAX) {
- throw new IllegalStateException("eventType " + eventType + " unknown");
- }
- return eventType;
- }
-
- @NonNull
- private static List<String> immutableList(@NonNull List<String> list) {
- Objects.requireNonNull(list);
- if (list.isEmpty()) {
- return Collections.emptyList();
- } else {
- return Collections.unmodifiableList(new ArrayList<>(list));
- }
- }
-}
diff --git a/location/java/com/android/internal/location/timezone/LocationTimeZoneProviderRequest.aidl b/location/java/com/android/internal/location/timezone/LocationTimeZoneProviderRequest.aidl
deleted file mode 100644
index bb59457..0000000
--- a/location/java/com/android/internal/location/timezone/LocationTimeZoneProviderRequest.aidl
+++ /dev/null
@@ -1,19 +0,0 @@
-/*
- * Copyright (C) 2020 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.internal.location.timezone;
-
-parcelable LocationTimeZoneProviderRequest;
diff --git a/location/java/com/android/internal/location/timezone/LocationTimeZoneProviderRequest.java b/location/java/com/android/internal/location/timezone/LocationTimeZoneProviderRequest.java
deleted file mode 100644
index 5c9d290..0000000
--- a/location/java/com/android/internal/location/timezone/LocationTimeZoneProviderRequest.java
+++ /dev/null
@@ -1,155 +0,0 @@
-/*
- * Copyright (C) 2020 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.internal.location.timezone;
-
-import android.annotation.NonNull;
-import android.os.Parcel;
-import android.os.Parcelable;
-
-import java.util.Objects;
-
-/**
- * A request passed to a location time zone provider to configure it.
- *
- * @hide
- */
-public final class LocationTimeZoneProviderRequest implements Parcelable {
-
- public static final LocationTimeZoneProviderRequest EMPTY_REQUEST =
- new LocationTimeZoneProviderRequest(
- false /* reportLocationTimeZone */,
- 0 /* initializationTimeoutMillis */);
-
- public static final Creator<LocationTimeZoneProviderRequest> CREATOR =
- new Creator<LocationTimeZoneProviderRequest>() {
- @Override
- public LocationTimeZoneProviderRequest createFromParcel(Parcel in) {
- return LocationTimeZoneProviderRequest.createFromParcel(in);
- }
-
- @Override
- public LocationTimeZoneProviderRequest[] newArray(int size) {
- return new LocationTimeZoneProviderRequest[size];
- }
- };
-
- private final boolean mReportLocationTimeZone;
-
- private final long mInitializationTimeoutMillis;
-
- private LocationTimeZoneProviderRequest(
- boolean reportLocationTimeZone, long initializationTimeoutMillis) {
- mReportLocationTimeZone = reportLocationTimeZone;
- mInitializationTimeoutMillis = initializationTimeoutMillis;
- }
-
- /**
- * Returns {@code true} if the provider should report events related to the device's current
- * time zone, {@code false} otherwise.
- */
- public boolean getReportLocationTimeZone() {
- return mReportLocationTimeZone;
- }
-
- // TODO(b/152744911) - once there are a couple of implementations, decide whether this needs to
- // be passed to the LocationTimeZoneProvider and remove if it is not useful.
- /**
- * Returns the maximum time that the provider is allowed to initialize before it is expected to
- * send an event of any sort. Only valid when {@link #getReportLocationTimeZone()} is {@code
- * true}. Failure to send an event in this time (with some fuzz) may be interpreted as if the
- * provider is uncertain of the time zone, and/or it could lead to the provider being disabled.
- */
- public long getInitializationTimeoutMillis() {
- return mInitializationTimeoutMillis;
- }
-
- @Override
- public int describeContents() {
- return 0;
- }
-
- @Override
- public void writeToParcel(Parcel parcel, int flags) {
- parcel.writeBoolean(mReportLocationTimeZone);
- parcel.writeLong(mInitializationTimeoutMillis);
- }
-
- static LocationTimeZoneProviderRequest createFromParcel(Parcel in) {
- boolean reportLocationTimeZone = in.readBoolean();
- long initializationTimeoutMillis = in.readLong();
- return new LocationTimeZoneProviderRequest(
- reportLocationTimeZone, initializationTimeoutMillis);
- }
-
- @Override
- public boolean equals(Object o) {
- if (this == o) {
- return true;
- }
- if (o == null || getClass() != o.getClass()) {
- return false;
- }
- LocationTimeZoneProviderRequest that = (LocationTimeZoneProviderRequest) o;
- return mReportLocationTimeZone == that.mReportLocationTimeZone
- && mInitializationTimeoutMillis == that.mInitializationTimeoutMillis;
- }
-
- @Override
- public int hashCode() {
- return Objects.hash(mReportLocationTimeZone, mInitializationTimeoutMillis);
- }
-
- @Override
- public String toString() {
- return "LocationTimeZoneProviderRequest{"
- + "mReportLocationTimeZone=" + mReportLocationTimeZone
- + ", mInitializationTimeoutMillis=" + mInitializationTimeoutMillis
- + "}";
- }
-
- /** @hide */
- public static final class Builder {
-
- private boolean mReportLocationTimeZone;
- private long mInitializationTimeoutMillis;
-
- /**
- * Sets the property that enables / disables the provider. This is set to {@code false} by
- * default.
- */
- public Builder setReportLocationTimeZone(boolean reportLocationTimeZone) {
- mReportLocationTimeZone = reportLocationTimeZone;
- return this;
- }
-
- /**
- * Sets the initialization timeout. See {@link
- * LocationTimeZoneProviderRequest#getInitializationTimeoutMillis()} for details.
- */
- public Builder setInitializationTimeoutMillis(long timeoutMillis) {
- mInitializationTimeoutMillis = timeoutMillis;
- return this;
- }
-
- /** Builds the {@link LocationTimeZoneProviderRequest} instance. */
- @NonNull
- public LocationTimeZoneProviderRequest build() {
- return new LocationTimeZoneProviderRequest(
- mReportLocationTimeZone, mInitializationTimeoutMillis);
- }
- }
-}
diff --git a/location/lib/api/current.txt b/location/lib/api/current.txt
index d4f7558..4e13487 100644
--- a/location/lib/api/current.txt
+++ b/location/lib/api/current.txt
@@ -67,35 +67,3 @@
}
-package com.android.location.timezone.provider {
-
- public final class LocationTimeZoneEventUnbundled {
- method public int getEventType();
- method @NonNull public java.util.List<java.lang.String> getTimeZoneIds();
- field public static final int EVENT_TYPE_PERMANENT_FAILURE = 1; // 0x1
- field public static final int EVENT_TYPE_SUCCESS = 2; // 0x2
- field public static final int EVENT_TYPE_UNCERTAIN = 3; // 0x3
- }
-
- public static final class LocationTimeZoneEventUnbundled.Builder {
- ctor public LocationTimeZoneEventUnbundled.Builder();
- method @NonNull public com.android.location.timezone.provider.LocationTimeZoneEventUnbundled build();
- method @NonNull public com.android.location.timezone.provider.LocationTimeZoneEventUnbundled.Builder setEventType(int);
- method @NonNull public com.android.location.timezone.provider.LocationTimeZoneEventUnbundled.Builder setTimeZoneIds(@NonNull java.util.List<java.lang.String>);
- }
-
- public abstract class LocationTimeZoneProviderBase {
- ctor public LocationTimeZoneProviderBase(android.content.Context, String);
- method public final android.os.IBinder getBinder();
- method protected final android.content.Context getContext();
- method protected abstract void onSetRequest(@NonNull com.android.location.timezone.provider.LocationTimeZoneProviderRequestUnbundled);
- method protected final void reportLocationTimeZoneEvent(@NonNull com.android.location.timezone.provider.LocationTimeZoneEventUnbundled);
- }
-
- public final class LocationTimeZoneProviderRequestUnbundled {
- method @IntRange(from=0) public long getInitializationTimeoutMillis();
- method public boolean getReportLocationTimeZone();
- }
-
-}
-
diff --git a/location/lib/java/com/android/location/provider/LocationProviderBase.java b/location/lib/java/com/android/location/provider/LocationProviderBase.java
index 54d8066..47e4256 100644
--- a/location/lib/java/com/android/location/provider/LocationProviderBase.java
+++ b/location/lib/java/com/android/location/provider/LocationProviderBase.java
@@ -23,6 +23,7 @@
import android.location.LocationManager;
import android.location.LocationProvider;
import android.location.LocationResult;
+import android.location.ProviderProperties;
import android.os.Build.VERSION_CODES;
import android.os.Bundle;
import android.os.IBinder;
@@ -35,7 +36,6 @@
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 java.io.FileDescriptor;
@@ -372,11 +372,7 @@
public void setLocationProviderManager(ILocationProviderManager manager) {
synchronized (mBinder) {
try {
- if (mPackageName != null || mAttributionTag != null) {
- manager.onSetIdentity(mPackageName, mAttributionTag);
- }
- manager.onSetProperties(mProperties);
- manager.onSetAllowed(mAllowed);
+ manager.onInitialize(mAllowed, mProperties, mPackageName, mAttributionTag);
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
} catch (RuntimeException e) {
diff --git a/location/lib/java/com/android/location/provider/ProviderPropertiesUnbundled.java b/location/lib/java/com/android/location/provider/ProviderPropertiesUnbundled.java
index 21ee5f4..9d8ccdf 100644
--- a/location/lib/java/com/android/location/provider/ProviderPropertiesUnbundled.java
+++ b/location/lib/java/com/android/location/provider/ProviderPropertiesUnbundled.java
@@ -17,8 +17,7 @@
package com.android.location.provider;
import android.annotation.NonNull;
-
-import com.android.internal.location.ProviderProperties;
+import android.location.ProviderProperties;
import java.util.Objects;
diff --git a/location/lib/java/com/android/location/timezone/provider/LocationTimeZoneEventUnbundled.java b/location/lib/java/com/android/location/timezone/provider/LocationTimeZoneEventUnbundled.java
deleted file mode 100644
index 55f5545..0000000
--- a/location/lib/java/com/android/location/timezone/provider/LocationTimeZoneEventUnbundled.java
+++ /dev/null
@@ -1,164 +0,0 @@
-/*
- * Copyright (C) 2020 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.location.timezone.provider;
-
-import android.annotation.IntDef;
-import android.annotation.NonNull;
-import android.os.SystemClock;
-
-import com.android.internal.location.timezone.LocationTimeZoneEvent;
-
-import java.util.Collections;
-import java.util.List;
-import java.util.Objects;
-
-/**
- * An event from a {@link LocationTimeZoneProviderBase} sent while determining a device's time zone
- * using its location.
- */
-public final class LocationTimeZoneEventUnbundled {
-
- @IntDef({ EVENT_TYPE_PERMANENT_FAILURE, EVENT_TYPE_SUCCESS, EVENT_TYPE_UNCERTAIN })
- @interface EventType {}
-
- /**
- * Indicates there was a permanent failure. This is not generally expected, and probably means a
- * required backend service has been turned down, or the client is unreasonably old.
- */
- public static final int EVENT_TYPE_PERMANENT_FAILURE =
- LocationTimeZoneEvent.EVENT_TYPE_PERMANENT_FAILURE;
-
- /**
- * Indicates a successful geolocation time zone detection event. {@link #getTimeZoneIds()} will
- * be non-null but can legitimately be empty, e.g. for disputed areas, oceans.
- */
- public static final int EVENT_TYPE_SUCCESS = LocationTimeZoneEvent.EVENT_TYPE_SUCCESS;
-
- /**
- * Indicates the time zone is not known because of an expected runtime state or error, e.g. when
- * the provider is unable to detect location, or there was a problem when resolving the location
- * to a time zone.
- */
- public static final int EVENT_TYPE_UNCERTAIN = LocationTimeZoneEvent.EVENT_TYPE_UNCERTAIN;
-
- @NonNull
- private final LocationTimeZoneEvent mDelegate;
-
- private LocationTimeZoneEventUnbundled(@NonNull LocationTimeZoneEvent delegate) {
- mDelegate = Objects.requireNonNull(delegate);
- }
-
- /**
- * Returns the event type.
- */
- public @EventType int getEventType() {
- return mDelegate.getEventType();
- }
-
- /**
- * Gets the time zone IDs of this event. Contains zero or more IDs for a successful lookup.
- * The value is undefined for an unsuccessful lookup. See also {@link #getEventType()}.
- */
- @NonNull
- public List<String> getTimeZoneIds() {
- return mDelegate.getTimeZoneIds();
- }
-
- /**
- * Returns the information from this as a {@link LocationTimeZoneEvent}.
- * @hide
- */
- @NonNull
- public LocationTimeZoneEvent getInternalLocationTimeZoneEvent() {
- return mDelegate;
- }
-
- @Override
- public String toString() {
- return "LocationTimeZoneEventUnbundled{"
- + "mDelegate=" + mDelegate
- + '}';
- }
-
- @Override
- public boolean equals(Object o) {
- if (this == o) {
- return true;
- }
- if (o == null || getClass() != o.getClass()) {
- return false;
- }
- LocationTimeZoneEventUnbundled that = (LocationTimeZoneEventUnbundled) o;
- return mDelegate.equals(that.mDelegate);
- }
-
- @Override
- public int hashCode() {
- return mDelegate.hashCode();
- }
-
- /**
- * A builder of {@link LocationTimeZoneEventUnbundled} instances.
- */
- public static final class Builder {
-
- private @EventType int mEventType;
- private @NonNull List<String> mTimeZoneIds = Collections.emptyList();
-
- /**
- * Set the time zone ID of this event.
- */
- @NonNull
- public Builder setEventType(@EventType int eventType) {
- checkValidEventType(eventType);
- mEventType = eventType;
- return this;
- }
-
- /**
- * Sets the time zone IDs of this event.
- */
- @NonNull
- public Builder setTimeZoneIds(@NonNull List<String> timeZoneIds) {
- mTimeZoneIds = Objects.requireNonNull(timeZoneIds);
- return this;
- }
-
- /**
- * Builds a {@link LocationTimeZoneEventUnbundled} instance.
- */
- @NonNull
- public LocationTimeZoneEventUnbundled build() {
- final int internalEventType = this.mEventType;
- LocationTimeZoneEvent event = new LocationTimeZoneEvent.Builder()
- .setEventType(internalEventType)
- .setTimeZoneIds(mTimeZoneIds)
- .setElapsedRealtimeMillis(SystemClock.elapsedRealtime())
- .build();
- return new LocationTimeZoneEventUnbundled(event);
- }
- }
-
- private static int checkValidEventType(int eventType) {
- if (eventType != EVENT_TYPE_SUCCESS
- && eventType != EVENT_TYPE_UNCERTAIN
- && eventType != EVENT_TYPE_PERMANENT_FAILURE) {
- throw new IllegalStateException("eventType=" + eventType);
- }
- return eventType;
- }
-}
diff --git a/location/lib/java/com/android/location/timezone/provider/LocationTimeZoneProviderBase.java b/location/lib/java/com/android/location/timezone/provider/LocationTimeZoneProviderBase.java
deleted file mode 100644
index 68ae722..0000000
--- a/location/lib/java/com/android/location/timezone/provider/LocationTimeZoneProviderBase.java
+++ /dev/null
@@ -1,119 +0,0 @@
-/*
- * Copyright (C) 2020 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.location.timezone.provider;
-
-import android.annotation.NonNull;
-import android.annotation.Nullable;
-import android.content.Context;
-import android.os.IBinder;
-import android.os.RemoteException;
-import android.util.Log;
-
-import com.android.internal.location.timezone.ILocationTimeZoneProvider;
-import com.android.internal.location.timezone.ILocationTimeZoneProviderManager;
-import com.android.internal.location.timezone.LocationTimeZoneProviderRequest;
-
-import java.util.Objects;
-
-/**
- * A base class for location time zone providers implemented as unbundled services.
- *
- * <p>Provider implementations are enabled / disabled via a call to {@link
- * #onSetRequest(LocationTimeZoneProviderRequestUnbundled)}.
- *
- * <p>Once enabled, providers are expected to detect the time zone if possible, and report the
- * result via {@link #reportLocationTimeZoneEvent(LocationTimeZoneEventUnbundled)} with a type of
- * either {@link LocationTimeZoneEventUnbundled#EVENT_TYPE_UNCERTAIN} or {@link
- * LocationTimeZoneEventUnbundled#EVENT_TYPE_SUCCESS}. Providers may also report that they have
- * permanently failed by sending an event of type {@link
- * LocationTimeZoneEventUnbundled#EVENT_TYPE_PERMANENT_FAILURE}. See the javadocs for each event
- * type for details.
- *
- * <p>Providers are expected to issue their first event within {@link
- * LocationTimeZoneProviderRequest#getInitializationTimeoutMillis()}.
- *
- * <p>Once disabled or have failed, providers are required to stop producing events.
- *
- * <p>Threading:
- *
- * <p>Calls to {@link #reportLocationTimeZoneEvent(LocationTimeZoneEventUnbundled)} can be made on
- * on any thread, but may be processed asynchronously by the system server. Similarly, calls to
- * {@link #onSetRequest(LocationTimeZoneProviderRequestUnbundled)} may occur on any thread.
- *
- * <p>IMPORTANT: This class is effectively a public API for unbundled applications, and must remain
- * API stable.
- */
-public abstract class LocationTimeZoneProviderBase {
-
- private final Context mContext;
- private final String mTag;
- private final IBinder mBinder;
-
- // write locked on mBinder, read lock is optional depending on atomicity requirements
- @Nullable private volatile ILocationTimeZoneProviderManager mManager;
-
- public LocationTimeZoneProviderBase(Context context, String tag) {
- mContext = context;
- mTag = tag;
- mBinder = new Service();
- mManager = null;
- }
-
- protected final Context getContext() {
- return mContext;
- }
-
- public final IBinder getBinder() {
- return mBinder;
- }
-
- /**
- * Reports a new location time zone event from this provider.
- */
- protected final void reportLocationTimeZoneEvent(
- @NonNull LocationTimeZoneEventUnbundled event) {
- ILocationTimeZoneProviderManager manager = mManager;
- if (manager != null) {
- try {
- manager.onLocationTimeZoneEvent(event.getInternalLocationTimeZoneEvent());
- } catch (RemoteException | RuntimeException e) {
- Log.w(mTag, e);
- }
- }
- }
-
- /**
- * Set the {@link LocationTimeZoneProviderRequestUnbundled} requirements for this provider. Each
- * call to this method overrides all previous requests. This method might trigger the provider
- * to start returning location time zones, or to stop returning location time zones, depending
- * on the parameters in the request.
- */
- protected abstract void onSetRequest(@NonNull LocationTimeZoneProviderRequestUnbundled request);
-
- private final class Service extends ILocationTimeZoneProvider.Stub {
-
- @Override
- public void setLocationTimeZoneProviderManager(ILocationTimeZoneProviderManager manager) {
- mManager = Objects.requireNonNull(manager);
- }
-
- @Override
- public void setRequest(LocationTimeZoneProviderRequest request) {
- onSetRequest(new LocationTimeZoneProviderRequestUnbundled(request));
- }
- }
-}
diff --git a/location/lib/java/com/android/location/timezone/provider/LocationTimeZoneProviderRequestUnbundled.java b/location/lib/java/com/android/location/timezone/provider/LocationTimeZoneProviderRequestUnbundled.java
deleted file mode 100644
index 10d1038..0000000
--- a/location/lib/java/com/android/location/timezone/provider/LocationTimeZoneProviderRequestUnbundled.java
+++ /dev/null
@@ -1,83 +0,0 @@
-/*
- * Copyright (C) 2020 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.location.timezone.provider;
-
-import android.annotation.IntRange;
-import android.annotation.NonNull;
-
-import com.android.internal.location.timezone.LocationTimeZoneProviderRequest;
-
-import java.util.Objects;
-
-/**
- * This class is an interface to LocationTimeZoneProviderRequest for provider implementations.
- *
- * <p>IMPORTANT: This class is effectively a public API for unbundled code, and must remain API
- * stable.
- */
-public final class LocationTimeZoneProviderRequestUnbundled {
-
- private final LocationTimeZoneProviderRequest mRequest;
-
- /** @hide */
- public LocationTimeZoneProviderRequestUnbundled(
- @NonNull LocationTimeZoneProviderRequest request) {
- mRequest = Objects.requireNonNull(request);
- }
-
- /**
- * Returns {@code true} if the provider should report events related to the device's current
- * time zone, {@code false} otherwise.
- */
- public boolean getReportLocationTimeZone() {
- return mRequest.getReportLocationTimeZone();
- }
-
- /**
- * Returns the maximum time that the provider is allowed to initialize before it is expected to
- * send an event of any sort. Only valid when {@link #getReportLocationTimeZone()} is {@code
- * true}. Failure to send an event in this time (with some fuzz) may be interpreted as if the
- * provider is uncertain of the time zone, and/or it could lead to the provider being disabled.
- */
- @IntRange(from = 0)
- public long getInitializationTimeoutMillis() {
- return mRequest.getInitializationTimeoutMillis();
- }
-
- @Override
- public boolean equals(Object o) {
- if (this == o) {
- return true;
- }
- if (o == null || getClass() != o.getClass()) {
- return false;
- }
- LocationTimeZoneProviderRequestUnbundled that =
- (LocationTimeZoneProviderRequestUnbundled) o;
- return mRequest.equals(that.mRequest);
- }
-
- @Override
- public int hashCode() {
- return Objects.hash(mRequest);
- }
-
- @Override
- public String toString() {
- return mRequest.toString();
- }
-}
diff --git a/media/java/android/media/MediaMetadataRetriever.java b/media/java/android/media/MediaMetadataRetriever.java
index 32a9168..c13f610 100644
--- a/media/java/android/media/MediaMetadataRetriever.java
+++ b/media/java/android/media/MediaMetadataRetriever.java
@@ -1374,17 +1374,13 @@
/**
* If the media contains XMP data, this key retrieves the offset (in bytes)
* of the data.
- * @hide
*/
- @SystemApi(client = MODULE_LIBRARIES)
public static final int METADATA_KEY_XMP_OFFSET = 41;
/**
* If the media contains XMP data, this key retrieves the length (in bytes)
* of the data.
- * @hide
*/
- @SystemApi(client = MODULE_LIBRARIES)
public static final int METADATA_KEY_XMP_LENGTH = 42;
// Add more here...
diff --git a/media/jni/Android.bp b/media/jni/Android.bp
index 79f6cbf..25b1b40 100644
--- a/media/jni/Android.bp
+++ b/media/jni/Android.bp
@@ -140,6 +140,7 @@
srcs: [
"android_media_tv_Tuner.cpp",
"tuner/DemuxClient.cpp",
+ "tuner/DvrClient.cpp",
"tuner/FilterClient.cpp",
"tuner/FrontendClient.cpp",
"tuner/TunerClient.cpp",
diff --git a/media/jni/android_media_tv_Tuner.cpp b/media/jni/android_media_tv_Tuner.cpp
index 6fa94f1..602364e 100644
--- a/media/jni/android_media_tv_Tuner.cpp
+++ b/media/jni/android_media_tv_Tuner.cpp
@@ -261,70 +261,38 @@
return mLnbSp;
}
-/////////////// DvrCallback ///////////////////////
-Return<void> DvrCallback::onRecordStatus(RecordStatus status) {
- ALOGD("DvrCallback::onRecordStatus");
+/////////////// DvrClientCallbackImpl ///////////////////////
+void DvrClientCallbackImpl::onRecordStatus(RecordStatus status) {
+ ALOGD("DvrClientCallbackImpl::onRecordStatus");
JNIEnv *env = AndroidRuntime::getJNIEnv();
env->CallVoidMethod(
- mDvr,
+ mDvrObj,
gFields.onDvrRecordStatusID,
(jint) status);
- return Void();
}
-Return<void> DvrCallback::onPlaybackStatus(PlaybackStatus status) {
- ALOGD("DvrCallback::onPlaybackStatus");
+void DvrClientCallbackImpl::onPlaybackStatus(PlaybackStatus status) {
+ ALOGD("DvrClientCallbackImpl::onPlaybackStatus");
JNIEnv *env = AndroidRuntime::getJNIEnv();
env->CallVoidMethod(
- mDvr,
+ mDvrObj,
gFields.onDvrPlaybackStatusID,
(jint) status);
- return Void();
}
-void DvrCallback::setDvr(const jobject dvr) {
- ALOGD("DvrCallback::setDvr");
- JNIEnv *env = AndroidRuntime::getJNIEnv();
- mDvr = env->NewWeakGlobalRef(dvr);
+void DvrClientCallbackImpl::setDvr(jweak dvrObj) {
+ ALOGD("DvrClientCallbackImpl::setDvr");
+ mDvrObj = dvrObj;
}
-DvrCallback::~DvrCallback() {
+DvrClientCallbackImpl::~DvrClientCallbackImpl() {
JNIEnv *env = AndroidRuntime::getJNIEnv();
- if (mDvr != NULL) {
- env->DeleteWeakGlobalRef(mDvr);
- mDvr = NULL;
+ if (mDvrObj != NULL) {
+ env->DeleteWeakGlobalRef(mDvrObj);
+ mDvrObj = NULL;
}
}
-/////////////// Dvr ///////////////////////
-
-Dvr::Dvr(sp<IDvr> sp, jobject obj) : mDvrSp(sp), mDvrMQEventFlag(nullptr) {
- JNIEnv *env = AndroidRuntime::getJNIEnv();
- mDvrObj = env->NewWeakGlobalRef(obj);
-}
-
-Dvr::~Dvr() {
- JNIEnv *env = AndroidRuntime::getJNIEnv();
- env->DeleteWeakGlobalRef(mDvrObj);
- mDvrObj = NULL;
-}
-
-jint Dvr::close() {
- Result r = mDvrSp->close();
- if (r == Result::SUCCESS) {
- EventFlag::deleteEventFlag(&mDvrMQEventFlag);
- }
- return (jint) r;
-}
-
-sp<IDvr> Dvr::getIDvr() {
- return mDvrSp;
-}
-
-MQ& Dvr::getDvrMQ() {
- return *mDvrMQ;
-}
-
/////////////// C2DataIdInfo ///////////////////////
C2DataIdInfo::C2DataIdInfo(uint32_t index, uint64_t value) : C2Param(kParamSize, index) {
@@ -1840,9 +1808,7 @@
jobject JTuner::openFilter(DemuxFilterType type, int bufferSize) {
if (mDemux == NULL || mDemuxClient == NULL) {
- if (openDemux() != Result::SUCCESS) {
- return NULL;
- }
+ return NULL;
}
sp<FilterClient> filterClient;
@@ -1906,21 +1872,14 @@
jobject JTuner::openDvr(DvrType type, jlong bufferSize) {
ALOGD("JTuner::openDvr");
- if (mDemux == NULL) {
- if (openDemux() != Result::SUCCESS) {
- return NULL;
- }
+ if (mDemuxClient == NULL) {
+ return NULL;
}
- sp<IDvr> iDvrSp;
- sp<DvrCallback> callback = new DvrCallback();
- Result res;
- mDemux->openDvr(type, (uint32_t) bufferSize, callback,
- [&](Result r, const sp<IDvr>& dvr) {
- res = r;
- iDvrSp = dvr;
- });
+ sp<DvrClient> dvrClient;
+ sp<DvrClientCallbackImpl> callback = new DvrClientCallbackImpl();
+ dvrClient = mDemuxClient->openDvr(type, (int) bufferSize, callback);
- if (res != Result::SUCCESS || iDvrSp == NULL) {
+ if (dvrClient == NULL) {
return NULL;
}
@@ -1932,21 +1891,19 @@
env->FindClass("android/media/tv/tuner/dvr/DvrRecorder"),
gFields.dvrRecorderInitID,
mObject);
- sp<Dvr> dvrSp = new Dvr(iDvrSp, dvrObj);
- dvrSp->incStrong(dvrObj);
- env->SetLongField(dvrObj, gFields.dvrRecorderContext, (jlong)dvrSp.get());
+ dvrClient->incStrong(dvrObj);
+ env->SetLongField(dvrObj, gFields.dvrRecorderContext, (jlong)dvrClient.get());
} else {
dvrObj =
env->NewObject(
env->FindClass("android/media/tv/tuner/dvr/DvrPlayback"),
gFields.dvrPlaybackInitID,
mObject);
- sp<Dvr> dvrSp = new Dvr(iDvrSp, dvrObj);
- dvrSp->incStrong(dvrObj);
- env->SetLongField(dvrObj, gFields.dvrPlaybackContext, (jlong)dvrSp.get());
+ dvrClient->incStrong(dvrObj);
+ env->SetLongField(dvrObj, gFields.dvrPlaybackContext, (jlong)dvrClient.get());
}
- callback->setDvr(dvrObj);
+ callback->setDvr(env->NewWeakGlobalRef(dvrObj));
return dvrObj;
}
@@ -3304,12 +3261,12 @@
return dvrSettings;
}
-static sp<Dvr> getDvr(JNIEnv *env, jobject dvr) {
+static sp<DvrClient> getDvrClient(JNIEnv *env, jobject dvr) {
bool isRecorder =
env->IsInstanceOf(dvr, env->FindClass("android/media/tv/tuner/dvr/DvrRecorder"));
jfieldID fieldId =
isRecorder ? gFields.dvrRecorderContext : gFields.dvrPlaybackContext;
- return (Dvr *)env->GetLongField(dvr, fieldId);
+ return (DvrClient *)env->GetLongField(dvr, fieldId);
}
static void android_media_tv_Tuner_native_init(JNIEnv *env) {
@@ -3910,33 +3867,6 @@
return filterClient->configureIpFilterContextId(cid);
}
-static jint copyData(JNIEnv *env, std::unique_ptr<MQ>& mq, EventFlag* flag, jbyteArray buffer,
- jlong offset, jlong size) {
- ALOGD("copyData, size=%ld, offset=%ld", (long) size, (long) offset);
-
- jlong available = mq->availableToRead();
- ALOGD("copyData, available=%ld", (long) available);
- size = std::min(size, available);
-
- jboolean isCopy;
- jbyte *dst = env->GetByteArrayElements(buffer, &isCopy);
- ALOGD("copyData, isCopy=%d", isCopy);
- if (dst == nullptr) {
- jniThrowRuntimeException(env, "Failed to GetByteArrayElements");
- return 0;
- }
-
- if (mq->read(reinterpret_cast<unsigned char*>(dst) + offset, size)) {
- env->ReleaseByteArrayElements(buffer, dst, 0);
- flag->wake(static_cast<uint32_t>(DemuxQueueNotifyBits::DATA_CONSUMED));
- } else {
- jniThrowRuntimeException(env, "Failed to read FMQ");
- env->ReleaseByteArrayElements(buffer, dst, 0);
- return 0;
- }
- return size;
-}
-
static bool isAvFilterSettings(DemuxFilterSettings filterSettings) {
return (filterSettings.getDiscriminator() == DemuxFilterSettings::hidl_discriminator::ts
&& filterSettings.ts().filterSettings.getDiscriminator()
@@ -4068,7 +3998,7 @@
if (filterClient == NULL) {
jniThrowException(env, "java/lang/IllegalStateException",
"Failed to read filter FMQ: filter client not found");
- return 0;
+ return -1;
}
jboolean isCopy;
@@ -4076,14 +4006,11 @@
ALOGD("copyData, isCopy=%d", isCopy);
if (dst == nullptr) {
jniThrowRuntimeException(env, "Failed to GetByteArrayElements");
- return 0;
+ return -1;
}
int realReadSize = filterClient->read(reinterpret_cast<uint8_t*>(dst) + offset, size);
env->ReleaseByteArrayElements(buffer, dst, 0);
- if (realReadSize < 0) {
- return (jint) Result::UNKNOWN_ERROR;
- }
- return (jint) Result::SUCCESS;
+ return (jint) realReadSize;
}
static jint android_media_tv_Tuner_close_filter(JNIEnv *env, jobject filter) {
@@ -4283,106 +4210,80 @@
}
static jint android_media_tv_Tuner_attach_filter(JNIEnv *env, jobject dvr, jobject filter) {
- sp<Dvr> dvrSp = getDvr(env, dvr);
- if (dvrSp == NULL) {
- return (jint) Result::NOT_INITIALIZED;
- }
sp<FilterClient> filterClient = getFilterClient(env, filter);
if (filterClient == NULL) {
return (jint) Result::INVALID_ARGUMENT;
}
- sp<IDvr> iDvrSp = dvrSp->getIDvr();
- // TODO: use filter client once dvrClient is ready
- sp<IFilter> iFilterSp = filterClient->getHalFilter();
- Result result = iDvrSp->attachFilter(iFilterSp);
+ sp<DvrClient> dvrClient = getDvrClient(env, dvr);
+ if (dvrClient == NULL) {
+ return (jint) Result::NOT_INITIALIZED;
+ }
+ Result result = dvrClient->attachFilter(filterClient);
return (jint) result;
}
static jint android_media_tv_Tuner_detach_filter(JNIEnv *env, jobject dvr, jobject filter) {
- sp<Dvr> dvrSp = getDvr(env, dvr);
- if (dvrSp == NULL) {
- return (jint) Result::NOT_INITIALIZED;
- }
sp<FilterClient> filterClient = getFilterClient(env, filter);
if (filterClient == NULL) {
return (jint) Result::INVALID_ARGUMENT;
}
- sp<IDvr> iDvrSp = dvrSp->getIDvr();
- // TODO: use filter client once dvrClient is ready
- sp<IFilter> iFilterSp = filterClient->getHalFilter();
- Result result = iDvrSp->detachFilter(iFilterSp);
+ sp<DvrClient> dvrClient = getDvrClient(env, dvr);
+ if (dvrClient == NULL) {
+ return (jint) Result::NOT_INITIALIZED;
+ }
+ Result result = dvrClient->detachFilter(filterClient);
return (jint) result;
}
static jint android_media_tv_Tuner_configure_dvr(JNIEnv *env, jobject dvr, jobject settings) {
- sp<Dvr> dvrSp = getDvr(env, dvr);
- if (dvrSp == NULL) {
- ALOGD("Failed to configure dvr: dvr not found");
+ sp<DvrClient> dvrClient = getDvrClient(env, dvr);
+ if (dvrClient == NULL) {
+ ALOGD("Failed to configure dvr: dvr client not found");
return (int)Result::NOT_INITIALIZED;
}
- sp<IDvr> iDvrSp = dvrSp->getIDvr();
bool isRecorder =
env->IsInstanceOf(dvr, env->FindClass("android/media/tv/tuner/dvr/DvrRecorder"));
- Result result = iDvrSp->configure(getDvrSettings(env, settings, isRecorder));
- if (result != Result::SUCCESS) {
- return (jint) result;
- }
- MQDescriptorSync<uint8_t> dvrMQDesc;
- Result getQueueDescResult = Result::UNKNOWN_ERROR;
- iDvrSp->getQueueDesc(
- [&](Result r, const MQDescriptorSync<uint8_t>& desc) {
- dvrMQDesc = desc;
- getQueueDescResult = r;
- ALOGD("getDvrQueueDesc");
- });
- if (getQueueDescResult == Result::SUCCESS) {
- dvrSp->mDvrMQ = std::make_unique<MQ>(dvrMQDesc, true);
- EventFlag::createEventFlag(
- dvrSp->mDvrMQ->getEventFlagWord(), &(dvrSp->mDvrMQEventFlag));
- }
- return (jint) getQueueDescResult;
+ Result result = dvrClient->configure(getDvrSettings(env, settings, isRecorder));
+ return (jint) result;
}
static jint android_media_tv_Tuner_start_dvr(JNIEnv *env, jobject dvr) {
- sp<Dvr> dvrSp = getDvr(env, dvr);
- if (dvrSp == NULL) {
- ALOGD("Failed to start dvr: dvr not found");
+ sp<DvrClient> dvrClient = getDvrClient(env, dvr);
+ if (dvrClient == NULL) {
+ ALOGD("Failed to start dvr: dvr client not found");
return (jint) Result::NOT_INITIALIZED;
}
- sp<IDvr> iDvrSp = dvrSp->getIDvr();
- Result result = iDvrSp->start();
+ Result result = dvrClient->start();
return (jint) result;
}
static jint android_media_tv_Tuner_stop_dvr(JNIEnv *env, jobject dvr) {
- sp<Dvr> dvrSp = getDvr(env, dvr);
- if (dvrSp == NULL) {
- ALOGD("Failed to stop dvr: dvr not found");
+ sp<DvrClient> dvrClient = getDvrClient(env, dvr);
+ if (dvrClient == NULL) {
+ ALOGD("Failed to stop dvr: dvr client not found");
return (jint) Result::NOT_INITIALIZED;
}
- sp<IDvr> iDvrSp = dvrSp->getIDvr();
- Result result = iDvrSp->stop();
+ Result result = dvrClient->stop();
return (jint) result;
}
static jint android_media_tv_Tuner_flush_dvr(JNIEnv *env, jobject dvr) {
- sp<Dvr> dvrSp = getDvr(env, dvr);
- if (dvrSp == NULL) {
- ALOGD("Failed to flush dvr: dvr not found");
+ sp<DvrClient> dvrClient = getDvrClient(env, dvr);
+ if (dvrClient == NULL) {
+ ALOGD("Failed to flush dvr: dvr client not found");
return (jint) Result::NOT_INITIALIZED;
}
- sp<IDvr> iDvrSp = dvrSp->getIDvr();
- Result result = iDvrSp->flush();
+ Result result = dvrClient->flush();
return (jint) result;
}
static jint android_media_tv_Tuner_close_dvr(JNIEnv* env, jobject dvr) {
- sp<Dvr> dvrSp = getDvr(env, dvr);
- if (dvrSp == NULL) {
- ALOGD("Failed to close dvr: dvr not found");
+ sp<DvrClient> dvrClient = getDvrClient(env, dvr);
+ if (dvrClient == NULL) {
+ ALOGD("Failed to close dvr: dvr client not found");
return (jint) Result::NOT_INITIALIZED;
}
- return dvrSp->close();
+ return (jint) dvrClient->close();
}
static sp<Lnb> getLnb(JNIEnv *env, jobject lnb) {
@@ -4427,170 +4328,76 @@
}
static void android_media_tv_Tuner_dvr_set_fd(JNIEnv *env, jobject dvr, jint fd) {
- sp<Dvr> dvrSp = getDvr(env, dvr);
- if (dvrSp == NULL) {
- ALOGD("Failed to set FD for dvr: dvr not found");
+ sp<DvrClient> dvrClient = getDvrClient(env, dvr);
+ if (dvrClient == NULL) {
+ ALOGD("Failed to set FD for dvr: dvr client not found");
+ return;
}
- dvrSp->mFd = (int) fd;
- ALOGD("set fd = %d", dvrSp->mFd);
+ dvrClient->setFd((int)fd);
+ ALOGD("set fd = %d", fd);
}
static jlong android_media_tv_Tuner_read_dvr(JNIEnv *env, jobject dvr, jlong size) {
- sp<Dvr> dvrSp = getDvr(env, dvr);
- if (dvrSp == NULL) {
+ sp<DvrClient> dvrClient = getDvrClient(env, dvr);
+ if (dvrClient == NULL) {
jniThrowException(env, "java/lang/IllegalStateException",
- "Failed to read dvr: dvr not found");
- return 0;
+ "Failed to read dvr: dvr client not found");
+ return -1;
}
- long available = dvrSp->mDvrMQ->availableToWrite();
- long write = std::min((long) size, available);
-
- MQ::MemTransaction tx;
- long ret = 0;
- if (dvrSp->mDvrMQ->beginWrite(write, &tx)) {
- auto first = tx.getFirstRegion();
- auto data = first.getAddress();
- long length = first.getLength();
- long firstToWrite = std::min(length, write);
- ret = read(dvrSp->mFd, data, firstToWrite);
-
- if (ret < 0) {
- ALOGE("[DVR] Failed to read from FD: %s", strerror(errno));
- jniThrowRuntimeException(env, strerror(errno));
- return 0;
- }
- if (ret < firstToWrite) {
- ALOGW("[DVR] file to MQ, first region: %ld bytes to write, but %ld bytes written",
- firstToWrite, ret);
- } else if (firstToWrite < write) {
- ALOGD("[DVR] write second region: %ld bytes written, %ld bytes in total", ret, write);
- auto second = tx.getSecondRegion();
- data = second.getAddress();
- length = second.getLength();
- int secondToWrite = std::min(length, write - firstToWrite);
- ret += read(dvrSp->mFd, data, secondToWrite);
- }
- ALOGD("[DVR] file to MQ: %ld bytes need to be written, %ld bytes written", write, ret);
- if (!dvrSp->mDvrMQ->commitWrite(ret)) {
- ALOGE("[DVR] Error: failed to commit write!");
- return 0;
- }
-
- } else {
- ALOGE("dvrMq.beginWrite failed");
- }
-
- if (ret > 0) {
- dvrSp->mDvrMQEventFlag->wake(static_cast<uint32_t>(DemuxQueueNotifyBits::DATA_READY));
- }
- return (jlong) ret;
+ return (jlong) dvrClient->readFromFile(size);
}
static jlong android_media_tv_Tuner_read_dvr_from_array(
JNIEnv* env, jobject dvr, jbyteArray buffer, jlong offset, jlong size) {
- sp<Dvr> dvrSp = getDvr(env, dvr);
- if (dvrSp == NULL) {
- ALOGW("Failed to read dvr: dvr not found");
- return 0;
+ sp<DvrClient> dvrClient = getDvrClient(env, dvr);
+ if (dvrClient == NULL) {
+ ALOGW("Failed to read dvr: dvr client not found");
+ return -1;
}
- if (dvrSp->mDvrMQ == NULL) {
- ALOGW("Failed to read dvr: dvr not configured");
- return 0;
- }
-
- jlong available = dvrSp->mDvrMQ->availableToWrite();
- size = std::min(size, available);
jboolean isCopy;
jbyte *src = env->GetByteArrayElements(buffer, &isCopy);
if (src == nullptr) {
ALOGD("Failed to GetByteArrayElements");
- return 0;
+ return -1;
}
+ long realSize = dvrClient->readFromBuffer(reinterpret_cast<unsigned char*>(src) + offset, size);
+ env->ReleaseByteArrayElements(buffer, src, 0);
+ return (jlong) realSize;
- if (dvrSp->mDvrMQ->write(reinterpret_cast<unsigned char*>(src) + offset, size)) {
- env->ReleaseByteArrayElements(buffer, src, 0);
- dvrSp->mDvrMQEventFlag->wake(static_cast<uint32_t>(DemuxQueueNotifyBits::DATA_READY));
- } else {
- ALOGD("Failed to write FMQ");
- env->ReleaseByteArrayElements(buffer, src, 0);
- return 0;
- }
- return size;
}
static jlong android_media_tv_Tuner_write_dvr(JNIEnv *env, jobject dvr, jlong size) {
- sp<Dvr> dvrSp = getDvr(env, dvr);
- if (dvrSp == NULL) {
+ sp<DvrClient> dvrClient = getDvrClient(env, dvr);
+ if (dvrClient == NULL) {
jniThrowException(env, "java/lang/IllegalStateException",
- "Failed to write dvr: dvr not found");
- return 0;
+ "Failed to write dvr: dvr client not found");
+ return -1;
}
- if (dvrSp->mDvrMQ == NULL) {
- jniThrowException(env, "java/lang/IllegalStateException",
- "Failed to write dvr: dvr not configured");
- return 0;
- }
-
- MQ& dvrMq = dvrSp->getDvrMQ();
-
- long available = dvrMq.availableToRead();
- long toRead = std::min((long) size, available);
-
- long ret = 0;
- MQ::MemTransaction tx;
- if (dvrMq.beginRead(toRead, &tx)) {
- auto first = tx.getFirstRegion();
- auto data = first.getAddress();
- long length = first.getLength();
- long firstToRead = std::min(length, toRead);
- ret = write(dvrSp->mFd, data, firstToRead);
-
- if (ret < 0) {
- ALOGE("[DVR] Failed to write to FD: %s", strerror(errno));
- jniThrowRuntimeException(env, strerror(errno));
- return 0;
- }
- if (ret < firstToRead) {
- ALOGW("[DVR] MQ to file: %ld bytes read, but %ld bytes written", firstToRead, ret);
- } else if (firstToRead < toRead) {
- ALOGD("[DVR] read second region: %ld bytes read, %ld bytes in total", ret, toRead);
- auto second = tx.getSecondRegion();
- data = second.getAddress();
- length = second.getLength();
- int secondToRead = toRead - firstToRead;
- ret += write(dvrSp->mFd, data, secondToRead);
- }
- ALOGD("[DVR] MQ to file: %ld bytes to be read, %ld bytes written", toRead, ret);
- if (!dvrMq.commitRead(ret)) {
- ALOGE("[DVR] Error: failed to commit read!");
- return 0;
- }
-
- } else {
- ALOGE("dvrMq.beginRead failed");
- }
- if (ret > 0) {
- dvrSp->mDvrMQEventFlag->wake(static_cast<uint32_t>(DemuxQueueNotifyBits::DATA_CONSUMED));
- }
-
- return (jlong) ret;
+ return (jlong) dvrClient->writeToFile(size);
}
static jlong android_media_tv_Tuner_write_dvr_to_array(
JNIEnv *env, jobject dvr, jbyteArray buffer, jlong offset, jlong size) {
- sp<Dvr> dvrSp = getDvr(env, dvr);
- if (dvrSp == NULL) {
- ALOGW("Failed to write dvr: dvr not found");
- return 0;
+ sp<DvrClient> dvrClient = getDvrClient(env, dvr);
+ if (dvrClient == NULL) {
+ ALOGW("Failed to read dvr: dvr client not found");
+ return -1;
}
- if (dvrSp->mDvrMQ == NULL) {
- ALOGW("Failed to write dvr: dvr not configured");
- return 0;
+
+ jboolean isCopy;
+ jbyte *dst = env->GetByteArrayElements(buffer, &isCopy);
+ ALOGD("copyData, isCopy=%d", isCopy);
+ if (dst == nullptr) {
+ jniThrowRuntimeException(env, "Failed to GetByteArrayElements");
+ return -1;
}
- return copyData(env, dvrSp->mDvrMQ, dvrSp->mDvrMQEventFlag, buffer, offset, size);
+
+ long realSize = dvrClient->writeToBuffer(reinterpret_cast<unsigned char*>(dst) + offset, size);
+ env->ReleaseByteArrayElements(buffer, dst, 0);
+ return (jlong) realSize;
}
static sp<MediaEvent> getMediaEventSp(JNIEnv *env, jobject mediaEventObj) {
diff --git a/media/jni/android_media_tv_Tuner.h b/media/jni/android_media_tv_Tuner.h
index 4149228..9dc4ddf 100644
--- a/media/jni/android_media_tv_Tuner.h
+++ b/media/jni/android_media_tv_Tuner.h
@@ -105,29 +105,14 @@
jweak mLnbObj;
};
-struct DvrCallback : public IDvrCallback {
- ~DvrCallback();
- virtual Return<void> onRecordStatus(RecordStatus status);
- virtual Return<void> onPlaybackStatus(PlaybackStatus status);
+struct DvrClientCallbackImpl : public DvrClientCallback {
+ ~DvrClientCallbackImpl();
+ virtual void onRecordStatus(RecordStatus status);
+ virtual void onPlaybackStatus(PlaybackStatus status);
- void setDvr(const jobject dvr);
+ void setDvr(jweak dvrObj);
private:
- jweak mDvr;
-};
-
-struct Dvr : public RefBase {
- Dvr(sp<IDvr> sp, jweak obj);
- ~Dvr();
- jint close();
- MQ& getDvrMQ();
- sp<IDvr> getIDvr();
- // TODO: remove after migrate to client lib
- sp<IDvr> mDvrSp;
jweak mDvrObj;
- std::unique_ptr<MQ> mDvrMQ;
- EventFlag* mDvrMQEventFlag;
- std::string mFilePath;
- int mFd;
};
struct MediaEvent : public RefBase {
diff --git a/media/jni/tuner/DemuxClient.cpp b/media/jni/tuner/DemuxClient.cpp
index b237a24..59dfd70 100644
--- a/media/jni/tuner/DemuxClient.cpp
+++ b/media/jni/tuner/DemuxClient.cpp
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-#define LOG_TAG "FrontendClient"
+#define LOG_TAG "DemuxClient"
#include <android-base/logging.h>
#include <utils/Log.h>
@@ -116,7 +116,21 @@
return -1;
}
-//DvrClient openDvr(int dvbType, int bufferSize, DvrClientCallback cb);
+sp<DvrClient> DemuxClient::openDvr(DvrType dvbType, int bufferSize, sp<DvrClientCallback> cb) {
+ // TODO: pending aidl interface
+
+ if (mDemux != NULL) {
+ sp<HidlDvrCallback> callback = new HidlDvrCallback(cb);
+ sp<IDvr> hidlDvr = openHidlDvr(dvbType, bufferSize, callback);
+ if (hidlDvr != NULL) {
+ sp<DvrClient> dvrClient = new DvrClient();
+ dvrClient->setHidlDvr(hidlDvr);
+ return dvrClient;
+ }
+ }
+
+ return NULL;
+}
Result DemuxClient::connectCiCam(int ciCamId) {
// pending aidl interface
@@ -173,4 +187,24 @@
return hidlFilter;
}
+
+sp<IDvr> DemuxClient::openHidlDvr(DvrType dvrType, int bufferSize,
+ sp<HidlDvrCallback> callback) {
+ if (mDemux == NULL) {
+ return NULL;
+ }
+
+ sp<IDvr> hidlDvr;
+ Result res;
+ mDemux->openDvr(dvrType, bufferSize, callback,
+ [&](Result r, const sp<IDvr>& dvr) {
+ hidlDvr = dvr;
+ res = r;
+ });
+ if (res != Result::SUCCESS || hidlDvr == NULL) {
+ return NULL;
+ }
+
+ return hidlDvr;
+}
} // namespace android
diff --git a/media/jni/tuner/DemuxClient.h b/media/jni/tuner/DemuxClient.h
index a0671a5..f11f2c6 100644
--- a/media/jni/tuner/DemuxClient.h
+++ b/media/jni/tuner/DemuxClient.h
@@ -21,6 +21,8 @@
#include <android/hardware/tv/tuner/1.0/IDemux.h>
#include <android/hardware/tv/tuner/1.1/types.h>
+#include "DvrClient.h"
+#include "DvrClientCallback.h"
#include "FilterClient.h"
#include "FilterClientCallback.h"
#include "FrontendClient.h"
@@ -28,6 +30,7 @@
//using ::aidl::android::media::tv::tuner::ITunerDemux;
using ::android::hardware::tv::tuner::V1_0::DemuxFilterType;
+using ::android::hardware::tv::tuner::V1_0::DvrType;
using ::android::hardware::tv::tuner::V1_0::IDemux;
using namespace std;
@@ -68,8 +71,7 @@
/**
* Open a DVR (Digital Video Record) client.
*/
- // TODO: handle DvrClient and callback
- //DvrClient openDvr(int dvbType, int bufferSize, DvrClientCallback cb);
+ sp<DvrClient> openDvr(DvrType dvbType, int bufferSize, sp<DvrClientCallback> cb);
/**
* Connect Conditional Access Modules (CAM) through Common Interface (CI).
@@ -88,6 +90,7 @@
private:
sp<IFilter> openHidlFilter(DemuxFilterType type, int bufferSize, sp<HidlFilterCallback> cb);
+ sp<IDvr> openHidlDvr(DvrType type, int bufferSize, sp<HidlDvrCallback> cb);
/**
* An AIDL Tuner Demux Singleton assigned at the first time the Tuner Client
diff --git a/media/jni/tuner/DvrClient.cpp b/media/jni/tuner/DvrClient.cpp
new file mode 100644
index 0000000..dd08491
--- /dev/null
+++ b/media/jni/tuner/DvrClient.cpp
@@ -0,0 +1,329 @@
+/*
+ * Copyright 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define LOG_TAG "DvrClient"
+
+#include <android-base/logging.h>
+#include <utils/Log.h>
+
+#include "DvrClient.h"
+
+using ::android::hardware::tv::tuner::V1_0::DemuxQueueNotifyBits;
+using ::android::hardware::tv::tuner::V1_0::Result;
+
+namespace android {
+
+/////////////// DvrClient ///////////////////////
+
+// TODO: pending aidl interface
+DvrClient::DvrClient() {
+ //mTunerDvr = tunerDvr;
+ mFd = -1;
+ mDvrMQ = NULL;
+ mDvrMQEventFlag = NULL;
+}
+
+DvrClient::~DvrClient() {
+ //mTunerDvr = NULL;
+ mDvr = NULL;
+ mFd = -1;
+ mDvrMQ = NULL;
+ mDvrMQEventFlag = NULL;
+}
+
+// TODO: remove after migration to Tuner Service is done.
+void DvrClient::setHidlDvr(sp<IDvr> dvr) {
+ mDvr = dvr;
+}
+
+void DvrClient::setFd(int fd) {
+ mFd = fd;
+}
+
+long DvrClient::readFromFile(long size) {
+ if (mDvrMQ == NULL || mDvrMQEventFlag == NULL) {
+ ALOGE("Failed to readFromFile. DVR mq is not configured");
+ return -1;
+ }
+ if (mFd < 0) {
+ ALOGE("Failed to readFromFile. File is not configured");
+ return -1;
+ }
+
+ long available = mDvrMQ->availableToWrite();
+ long write = min(size, available);
+
+ MQ::MemTransaction tx;
+ long ret = 0;
+ if (mDvrMQ->beginWrite(write, &tx)) {
+ auto first = tx.getFirstRegion();
+ auto data = first.getAddress();
+ long length = first.getLength();
+ long firstToWrite = min(length, write);
+ ret = read(mFd, data, firstToWrite);
+
+ if (ret < 0) {
+ ALOGE("Failed to read from FD: %s", strerror(errno));
+ return -1;
+ }
+ if (ret < firstToWrite) {
+ ALOGW("file to MQ, first region: %ld bytes to write, but %ld bytes written",
+ firstToWrite, ret);
+ } else if (firstToWrite < write) {
+ ALOGD("write second region: %ld bytes written, %ld bytes in total", ret, write);
+ auto second = tx.getSecondRegion();
+ data = second.getAddress();
+ length = second.getLength();
+ int secondToWrite = std::min(length, write - firstToWrite);
+ ret += read(mFd, data, secondToWrite);
+ }
+ ALOGD("file to MQ: %ld bytes need to be written, %ld bytes written", write, ret);
+ if (!mDvrMQ->commitWrite(ret)) {
+ ALOGE("Error: failed to commit write!");
+ return -1;
+ }
+ } else {
+ ALOGE("dvrMq.beginWrite failed");
+ }
+
+ if (ret > 0) {
+ mDvrMQEventFlag->wake(static_cast<uint32_t>(DemuxQueueNotifyBits::DATA_READY));
+ }
+ return ret;
+}
+
+long DvrClient::readFromBuffer(uint8_t* buffer, long size) {
+ if (mDvrMQ == NULL || mDvrMQEventFlag == NULL) {
+ ALOGE("Failed to readFromBuffer. DVR mq is not configured");
+ return -1;
+ }
+ if (buffer == nullptr) {
+ ALOGE("Failed to readFromBuffer. Buffer can't be null");
+ return -1;
+ }
+
+ long available = mDvrMQ->availableToWrite();
+ size = min(size, available);
+
+ if (mDvrMQ->write(buffer, size)) {
+ mDvrMQEventFlag->wake(static_cast<uint32_t>(DemuxQueueNotifyBits::DATA_READY));
+ } else {
+ ALOGD("Failed to write FMQ");
+ return -1;
+ }
+ return size;
+}
+
+long DvrClient::writeToFile(long size) {
+ if (mDvrMQ == NULL || mDvrMQEventFlag == NULL) {
+ ALOGE("Failed to writeToFile. DVR mq is not configured");
+ return -1;
+ }
+ if (mFd < 0) {
+ ALOGE("Failed to writeToFile. File is not configured");
+ return -1;
+ }
+
+ long available = mDvrMQ->availableToRead();
+ long toRead = min(size, available);
+
+ long ret = 0;
+ MQ::MemTransaction tx;
+ if (mDvrMQ->beginRead(toRead, &tx)) {
+ auto first = tx.getFirstRegion();
+ auto data = first.getAddress();
+ long length = first.getLength();
+ long firstToRead = std::min(length, toRead);
+ ret = write(mFd, data, firstToRead);
+
+ if (ret < 0) {
+ ALOGE("Failed to write to FD: %s", strerror(errno));
+ return -1;
+ }
+ if (ret < firstToRead) {
+ ALOGW("MQ to file: %ld bytes read, but %ld bytes written", firstToRead, ret);
+ } else if (firstToRead < toRead) {
+ ALOGD("read second region: %ld bytes read, %ld bytes in total", ret, toRead);
+ auto second = tx.getSecondRegion();
+ data = second.getAddress();
+ length = second.getLength();
+ int secondToRead = toRead - firstToRead;
+ ret += write(mFd, data, secondToRead);
+ }
+ ALOGD("MQ to file: %ld bytes to be read, %ld bytes written", toRead, ret);
+ if (!mDvrMQ->commitRead(ret)) {
+ ALOGE("Error: failed to commit read!");
+ return 0;
+ }
+ } else {
+ ALOGE("dvrMq.beginRead failed");
+ }
+ if (ret > 0) {
+ mDvrMQEventFlag->wake(static_cast<uint32_t>(DemuxQueueNotifyBits::DATA_CONSUMED));
+ }
+
+ return ret;
+}
+
+long DvrClient::writeToBuffer(uint8_t* buffer, long size) {
+ if (mDvrMQ == NULL || mDvrMQEventFlag == NULL) {
+ ALOGE("Failed to writetoBuffer. DVR mq is not configured");
+ return -1;
+ }
+ if (buffer == nullptr) {
+ ALOGE("Failed to writetoBuffer. Buffer can't be null");
+ return -1;
+ }
+
+ long available = mDvrMQ->availableToRead();
+ size = min(size, available);
+
+ if (mDvrMQ->read(buffer, size)) {
+ mDvrMQEventFlag->wake(static_cast<uint32_t>(DemuxQueueNotifyBits::DATA_CONSUMED));
+ } else {
+ ALOGD("Failed to write FMQ");
+ return -1;
+ }
+ return size;
+}
+
+Result DvrClient::configure(DvrSettings settings) {
+ // pending aidl interface
+
+ if (mDvr != NULL) {
+ Result res = mDvr->configure(settings);
+ if (res == Result::SUCCESS) {
+ MQDescriptorSync<uint8_t> dvrMQDesc;
+ res = getQueueDesc(dvrMQDesc);
+ if (res == Result::SUCCESS) {
+ mDvrMQ = make_unique<MQ>(dvrMQDesc, true);
+ EventFlag::createEventFlag(mDvrMQ->getEventFlagWord(), &mDvrMQEventFlag);
+ }
+ }
+ return res;
+ }
+
+ return Result::INVALID_STATE;
+}
+
+Result DvrClient::attachFilter(sp<FilterClient> filterClient) {
+ // pending aidl interface
+
+ if (mDvr != NULL) {
+ sp<IFilter> hidlFilter = filterClient->getHalFilter();
+ if (hidlFilter == NULL) {
+ return Result::INVALID_ARGUMENT;
+ }
+ return mDvr->attachFilter(hidlFilter);
+ }
+
+ return Result::INVALID_STATE;
+}
+
+Result DvrClient::detachFilter(sp<FilterClient> filterClient) {
+ // pending aidl interface
+
+ if (mDvr != NULL) {
+ sp<IFilter> hidlFilter = filterClient->getHalFilter();
+ if (hidlFilter == NULL) {
+ return Result::INVALID_ARGUMENT;
+ }
+ return mDvr->detachFilter(hidlFilter);
+ }
+
+ return Result::INVALID_STATE;
+}
+
+Result DvrClient::start() {
+ // pending aidl interface
+
+ if (mDvr != NULL) {
+ return mDvr->start();
+ }
+
+ return Result::INVALID_STATE;
+}
+
+Result DvrClient::stop() {
+ // pending aidl interface
+
+ if (mDvr != NULL) {
+ return mDvr->stop();
+ }
+
+ return Result::INVALID_STATE;
+}
+
+Result DvrClient::flush() {
+ // pending aidl interface
+
+ if (mDvr != NULL) {
+ return mDvr->flush();
+ }
+
+ return Result::INVALID_STATE;
+}
+
+Result DvrClient::close() {
+ // pending aidl interface
+
+ if (mDvr != NULL) {
+ Result res = mDvr->close();
+ if (res == Result::SUCCESS) {
+ mDvr = NULL;
+ }
+ return res;
+ }
+
+ return Result::INVALID_STATE;
+}
+
+/////////////// IDvrCallback ///////////////////////
+
+HidlDvrCallback::HidlDvrCallback(sp<DvrClientCallback> dvrClientCallback)
+ : mDvrClientCallback(dvrClientCallback) {}
+
+Return<void> HidlDvrCallback::onRecordStatus(const RecordStatus status) {
+ if (mDvrClientCallback != NULL) {
+ mDvrClientCallback->onRecordStatus(status);
+ }
+ return Void();
+}
+
+Return<void> HidlDvrCallback::onPlaybackStatus(const PlaybackStatus status) {
+ if (mDvrClientCallback != NULL) {
+ mDvrClientCallback->onPlaybackStatus(status);
+ }
+ return Void();
+}
+
+/////////////// DvrClient Helper Methods ///////////////////////
+
+Result DvrClient::getQueueDesc(MQDesc& dvrMQDesc) {
+ // pending aidl interface
+
+ if (mDvr != NULL) {
+ Result res = Result::UNKNOWN_ERROR;
+ mDvr->getQueueDesc([&](Result r, const MQDesc& desc) {
+ dvrMQDesc = desc;
+ res = r;
+ });
+ return res;
+ }
+
+ return Result::INVALID_STATE;
+}
+} // namespace android
diff --git a/media/jni/tuner/DvrClient.h b/media/jni/tuner/DvrClient.h
new file mode 100644
index 0000000..2aba5e0
--- /dev/null
+++ b/media/jni/tuner/DvrClient.h
@@ -0,0 +1,162 @@
+/*
+ * Copyright 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef _ANDROID_MEDIA_TV_DVR_CLIENT_H_
+#define _ANDROID_MEDIA_TV_DVR_CLIENT_H_
+
+//#include <aidl/android/media/tv/tuner/ITunerDvr.h>
+#include <android/hardware/tv/tuner/1.0/IDvr.h>
+#include <android/hardware/tv/tuner/1.0/IDvrCallback.h>
+#include <android/hardware/tv/tuner/1.1/types.h>
+#include <fmq/MessageQueue.h>
+
+#include "DvrClientCallback.h"
+#include "FilterClient.h"
+
+//using ::aidl::android::media::tv::tuner::ITunerDvr;
+
+using ::android::hardware::EventFlag;
+using ::android::hardware::MQDescriptorSync;
+using ::android::hardware::MessageQueue;
+using ::android::hardware::tv::tuner::V1_0::DvrSettings;
+using ::android::hardware::tv::tuner::V1_0::IDvr;
+using ::android::hardware::tv::tuner::V1_0::IDvrCallback;
+
+using namespace std;
+
+using MQ = MessageQueue<uint8_t, kSynchronizedReadWrite>;
+using MQDesc = MQDescriptorSync<uint8_t>;
+
+namespace android {
+
+// TODO: pending aidl interface
+/*class TunerDvrCallback : public BnTunerDvrCallback {
+
+public:
+ TunerDvrCallback(sp<DvrClientCallback> dvrClientCallback);
+
+ Status onRecordStatus(int status);
+ Status onPlaybackStatus(int status);
+
+private:
+ sp<DvrClientCallback> mDvrClientCallback;
+};*/
+
+struct HidlDvrCallback : public IDvrCallback {
+
+public:
+ HidlDvrCallback(sp<DvrClientCallback> dvrClientCallback);
+ virtual Return<void> onRecordStatus(const RecordStatus status);
+ virtual Return<void> onPlaybackStatus(const PlaybackStatus status);
+
+private:
+ sp<DvrClientCallback> mDvrClientCallback;
+};
+
+struct DvrClient : public RefBase {
+
+public:
+ DvrClient();
+ ~DvrClient();
+
+ // TODO: remove after migration to Tuner Service is done.
+ void setHidlDvr(sp<IDvr> dvr);
+
+ /**
+ * Set the DVR file descriptor.
+ */
+ void setFd(int fd);
+
+ /**
+ * Read data from file with given size. Return the actual read size.
+ */
+ long readFromFile(long size);
+
+ /**
+ * Read data from the given buffer with given size. Return the actual read size.
+ */
+ long readFromBuffer(uint8_t* buffer, long size);
+
+ /**
+ * Write data to file with given size. Return the actual write size.
+ */
+ long writeToFile(long size);
+
+ /**
+ * Write data to the given buffer with given size. Return the actual write size.
+ */
+ long writeToBuffer(uint8_t* buffer, long size);
+
+ /**
+ * Configure the DVR.
+ */
+ Result configure(DvrSettings settings);
+
+ /**
+ * Attach one filter to DVR interface for recording.
+ */
+ Result attachFilter(sp<FilterClient> filterClient);
+
+ /**
+ * Detach one filter from the DVR's recording.
+ */
+ Result detachFilter(sp<FilterClient> filterClient);
+
+ /**
+ * Start DVR.
+ */
+ Result start();
+
+ /**
+ * Stop DVR.
+ */
+ Result stop();
+
+ /**
+ * Flush DVR data.
+ */
+ Result flush();
+
+ /**
+ * close the DVR instance to release resource for DVR.
+ */
+ Result close();
+
+private:
+ Result getQueueDesc(MQDesc& dvrMQDesc);
+
+ /**
+ * An AIDL Tuner Dvr Singleton assigned at the first time the Tuner Client
+ * opens a dvr. Default null when dvr is not opened.
+ */
+ // TODO: pending on aidl interface
+ //shared_ptr<ITunerDvr> mTunerDvr;
+
+ /**
+ * A Dvr HAL interface that is ready before migrating to the TunerDvr.
+ * This is a temprary interface before Tuner Framework migrates to use TunerService.
+ * Default null when the HAL service does not exist.
+ */
+ sp<IDvr> mDvr;
+
+ unique_ptr<MQ> mDvrMQ;
+ EventFlag* mDvrMQEventFlag;
+ string mFilePath;
+ int mFd;
+};
+} // namespace android
+
+#endif // _ANDROID_MEDIA_TV_DVR_CLIENT_H_
diff --git a/media/jni/tuner/DvrClientCallback.h b/media/jni/tuner/DvrClientCallback.h
new file mode 100644
index 0000000..6684424
--- /dev/null
+++ b/media/jni/tuner/DvrClientCallback.h
@@ -0,0 +1,33 @@
+/*
+ * Copyright 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef _ANDROID_MEDIA_TV_DVR_CLIENT_CALLBACK_H_
+#define _ANDROID_MEDIA_TV_DVR_CLIENT_CALLBACK_H_
+
+using ::android::hardware::tv::tuner::V1_0::PlaybackStatus;
+using ::android::hardware::tv::tuner::V1_0::RecordStatus;
+
+using namespace std;
+
+namespace android {
+
+struct DvrClientCallback : public RefBase {
+ virtual void onRecordStatus(const RecordStatus status);
+ virtual void onPlaybackStatus(const PlaybackStatus status);
+};
+} // namespace android
+
+#endif // _ANDROID_MEDIA_TV_DVR_CLIENT_CALLBACK_H_
\ No newline at end of file
diff --git a/media/jni/tuner/TunerClient.cpp b/media/jni/tuner/TunerClient.cpp
index 2c1735f..bd18c707 100644
--- a/media/jni/tuner/TunerClient.cpp
+++ b/media/jni/tuner/TunerClient.cpp
@@ -40,6 +40,8 @@
// Connect with Tuner Service.
::ndk::SpAIBinder binder(AServiceManager_getService("media.tuner"));
mTunerService = ITunerService::fromBinder(binder);
+ // TODO: Remove after JNI migration is done.
+ mTunerService = NULL;
if (mTunerService == NULL) {
ALOGE("Failed to get tuner service");
}
diff --git a/native/graphics/OWNERS b/native/graphics/OWNERS
index a6d1bc3..d81ea2c 100644
--- a/native/graphics/OWNERS
+++ b/native/graphics/OWNERS
@@ -1 +1 @@
-include /core/java/android/graphics/OWNERS
+include /graphics/java/android/graphics/OWNERS
diff --git a/packages/DynamicSystemInstallationService/src/com/android/dynsystem/DynamicSystemInstallationService.java b/packages/DynamicSystemInstallationService/src/com/android/dynsystem/DynamicSystemInstallationService.java
index a4896cb2..7f19662 100644
--- a/packages/DynamicSystemInstallationService/src/com/android/dynsystem/DynamicSystemInstallationService.java
+++ b/packages/DynamicSystemInstallationService/src/com/android/dynsystem/DynamicSystemInstallationService.java
@@ -74,7 +74,7 @@
public class DynamicSystemInstallationService extends Service
implements InstallationAsyncTask.ProgressListener {
- private static final String TAG = "DynSystemInstallationService";
+ private static final String TAG = "DynamicSystemInstallationService";
// TODO (b/131866826): This is currently for test only. Will move this to System API.
static final String KEY_ENABLE_WHEN_COMPLETED = "KEY_ENABLE_WHEN_COMPLETED";
diff --git a/packages/DynamicSystemInstallationService/src/com/android/dynsystem/InstallationAsyncTask.java b/packages/DynamicSystemInstallationService/src/com/android/dynsystem/InstallationAsyncTask.java
index ac73f35..4ef5e2b 100644
--- a/packages/DynamicSystemInstallationService/src/com/android/dynsystem/InstallationAsyncTask.java
+++ b/packages/DynamicSystemInstallationService/src/com/android/dynsystem/InstallationAsyncTask.java
@@ -20,6 +20,7 @@
import android.gsi.AvbPublicKey;
import android.net.Uri;
import android.os.AsyncTask;
+import android.os.Build;
import android.os.MemoryFile;
import android.os.ParcelFileDescriptor;
import android.os.image.DynamicSystemManager;
@@ -51,7 +52,8 @@
private static final long MIN_PROGRESS_TO_PUBLISH = 1 << 27;
private static final List<String> UNSUPPORTED_PARTITIONS =
- Arrays.asList("vbmeta", "boot", "userdata", "dtbo", "super_empty", "system_other");
+ Arrays.asList(
+ "vbmeta", "boot", "userdata", "dtbo", "super_empty", "system_other", "scratch");
private class UnsupportedUrlException extends Exception {
private UnsupportedUrlException(String message) {
@@ -196,6 +198,22 @@
return null;
}
+ if (Build.IS_DEBUGGABLE) {
+ // If host is debuggable, then install a scratch partition so that we can do
+ // adb remount in the guest system.
+ try {
+ installScratch();
+ } catch (IOException e) {
+ // Failing to install overlayFS scratch shouldn't be fatal.
+ // Just ignore the error and skip installing the scratch partition.
+ Log.w(TAG, e.toString(), e);
+ }
+ if (isCancelled()) {
+ mDynSystem.remove();
+ return null;
+ }
+ }
+
mDynSystem.finishInstallation();
} catch (Exception e) {
Log.e(TAG, e.toString(), e);
@@ -302,12 +320,53 @@
}
}
- private void installUserdata() throws Exception {
+ private void installScratch() throws IOException, InterruptedException {
+ final long scratchSize = mDynSystem.suggestScratchSize();
+ Thread thread = new Thread() {
+ @Override
+ public void run() {
+ mInstallationSession =
+ mDynSystem.createPartition("scratch", scratchSize, /* readOnly= */ false);
+ }
+ };
+
+ Log.d(TAG, "Creating partition: scratch, size = " + scratchSize);
+ thread.start();
+
+ Progress progress = new Progress("scratch", scratchSize, mNumInstalledPartitions++);
+
+ while (thread.isAlive()) {
+ if (isCancelled()) {
+ return;
+ }
+
+ final long installedSize = mDynSystem.getInstallationProgress().bytes_processed;
+
+ if (installedSize > progress.installedSize + MIN_PROGRESS_TO_PUBLISH) {
+ progress.installedSize = installedSize;
+ publishProgress(progress);
+ }
+
+ Thread.sleep(100);
+ }
+
+ if (mInstallationSession == null) {
+ throw new IOException(
+ "Failed to start installation with requested size: " + scratchSize);
+ }
+ // Reset installation session and verify that installation completes successfully.
+ mInstallationSession = null;
+ if (!mDynSystem.closePartition()) {
+ throw new IOException("Failed to complete partition installation: scratch");
+ }
+ }
+
+ private void installUserdata() throws IOException, InterruptedException {
Thread thread = new Thread(() -> {
mInstallationSession = mDynSystem.createPartition("userdata", mUserdataSize, false);
});
- Log.d(TAG, "Creating partition: userdata");
+ Log.d(TAG, "Creating partition: userdata, size = " + mUserdataSize);
thread.start();
Progress progress = new Progress("userdata", mUserdataSize, mNumInstalledPartitions++);
@@ -324,7 +383,7 @@
publishProgress(progress);
}
- Thread.sleep(10);
+ Thread.sleep(100);
}
if (mInstallationSession == null) {
@@ -445,7 +504,7 @@
return;
}
- Thread.sleep(10);
+ Thread.sleep(100);
}
if (mInstallationSession == null) {
diff --git a/packages/FusedLocation/test/src/com/android/location/fused/tests/FusedLocationServiceTest.java b/packages/FusedLocation/test/src/com/android/location/fused/tests/FusedLocationServiceTest.java
index f9f1607..2bda530 100644
--- a/packages/FusedLocation/test/src/com/android/location/fused/tests/FusedLocationServiceTest.java
+++ b/packages/FusedLocation/test/src/com/android/location/fused/tests/FusedLocationServiceTest.java
@@ -27,6 +27,7 @@
import android.location.LocationManager;
import android.location.LocationRequest;
import android.location.LocationResult;
+import android.location.ProviderProperties;
import android.os.ParcelFileDescriptor;
import android.os.SystemClock;
import android.os.WorkSource;
@@ -37,7 +38,6 @@
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.location.fused.FusedLocationProvider;
@@ -153,7 +153,8 @@
}
@Override
- public void onSetIdentity(String packageName, String attributionTag) {
+ public void onInitialize(boolean allowed, ProviderProperties properties, String packageName,
+ String attributionTag) {
}
diff --git a/packages/SettingsLib/RadioButtonPreference/res/drawable/ic_settings_accent.xml b/packages/SettingsLib/RadioButtonPreference/res/drawable/ic_settings_accent.xml
new file mode 100644
index 0000000..6521bc9
--- /dev/null
+++ b/packages/SettingsLib/RadioButtonPreference/res/drawable/ic_settings_accent.xml
@@ -0,0 +1,29 @@
+<!--
+ Copyright (C) 2021 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.
+ -->
+
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="24dp"
+ android:height="24dp"
+ android:viewportWidth="24.0"
+ android:viewportHeight="24.0"
+ android:tint="?android:attr/colorAccent">
+ <path
+ android:fillColor="#FFFFFFFF"
+ android:pathData="M13.85,22.25h-3.7c-0.74,0 -1.36,-0.54 -1.45,-1.27l-0.27,-1.89c-0.27,-0.14 -0.53,-0.29 -0.79,-0.46l-1.8,0.72c-0.7,0.26 -1.47,-0.03 -1.81,-0.65L2.2,15.53c-0.35,-0.66 -0.2,-1.44 0.36,-1.88l1.53,-1.19c-0.01,-0.15 -0.02,-0.3 -0.02,-0.46c0,-0.15 0.01,-0.31 0.02,-0.46l-1.52,-1.19C1.98,9.9 1.83,9.09 2.2,8.47l1.85,-3.19c0.34,-0.62 1.11,-0.9 1.79,-0.63l1.81,0.73c0.26,-0.17 0.52,-0.32 0.78,-0.46l0.27,-1.91c0.09,-0.7 0.71,-1.25 1.44,-1.25h3.7c0.74,0 1.36,0.54 1.45,1.27l0.27,1.89c0.27,0.14 0.53,0.29 0.79,0.46l1.8,-0.72c0.71,-0.26 1.48,0.03 1.82,0.65l1.84,3.18c0.36,0.66 0.2,1.44 -0.36,1.88l-1.52,1.19c0.01,0.15 0.02,0.3 0.02,0.46s-0.01,0.31 -0.02,0.46l1.52,1.19c0.56,0.45 0.72,1.23 0.37,1.86l-1.86,3.22c-0.34,0.62 -1.11,0.9 -1.8,0.63l-1.8,-0.72c-0.26,0.17 -0.52,0.32 -0.78,0.46l-0.27,1.91C15.21,21.71 14.59,22.25 13.85,22.25zM13.32,20.72c0,0.01 0,0.01 0,0.02L13.32,20.72zM10.68,20.7l0,0.02C10.69,20.72 10.69,20.71 10.68,20.7zM10.62,20.25h2.76l0.37,-2.55l0.53,-0.22c0.44,-0.18 0.88,-0.44 1.34,-0.78l0.45,-0.34l2.38,0.96l1.38,-2.4l-2.03,-1.58l0.07,-0.56c0.03,-0.26 0.06,-0.51 0.06,-0.78c0,-0.27 -0.03,-0.53 -0.06,-0.78l-0.07,-0.56l2.03,-1.58l-1.39,-2.4l-2.39,0.96l-0.45,-0.35c-0.42,-0.32 -0.87,-0.58 -1.33,-0.77L13.75,6.3l-0.37,-2.55h-2.76L10.25,6.3L9.72,6.51C9.28,6.7 8.84,6.95 8.38,7.3L7.93,7.63L5.55,6.68L4.16,9.07l2.03,1.58l-0.07,0.56C6.09,11.47 6.06,11.74 6.06,12c0,0.26 0.02,0.53 0.06,0.78l0.07,0.56l-2.03,1.58l1.38,2.4l2.39,-0.96l0.45,0.35c0.43,0.33 0.86,0.58 1.33,0.77l0.53,0.22L10.62,20.25zM18.22,17.72c0,0.01 -0.01,0.02 -0.01,0.03L18.22,17.72zM5.77,17.71l0.01,0.02C5.78,17.72 5.77,17.71 5.77,17.71zM3.93,9.47L3.93,9.47C3.93,9.47 3.93,9.47 3.93,9.47zM18.22,6.27c0,0.01 0.01,0.02 0.01,0.02L18.22,6.27zM5.79,6.25L5.78,6.27C5.78,6.27 5.79,6.26 5.79,6.25zM13.31,3.28c0,0.01 0,0.01 0,0.02L13.31,3.28zM10.69,3.26l0,0.02C10.69,3.27 10.69,3.27 10.69,3.26z"/>
+ <path
+ android:fillColor="#FFFFFFFF"
+ android:pathData="M12,12m-3.5,0a3.5,3.5 0,1 1,7 0a3.5,3.5 0,1 1,-7 0"/>
+</vector>
\ No newline at end of file
diff --git a/packages/SettingsLib/RadioButtonPreference/res/layout/preference_radio.xml b/packages/SettingsLib/RadioButtonPreference/res/layout/preference_radio.xml
index b4b4c63..5ff0dc7 100644
--- a/packages/SettingsLib/RadioButtonPreference/res/layout/preference_radio.xml
+++ b/packages/SettingsLib/RadioButtonPreference/res/layout/preference_radio.xml
@@ -92,16 +92,32 @@
android:textAlignment="viewEnd"
android:textColor="?android:attr/textColorSecondary"
android:maxLines="1"
+ android:visibility="gone"
android:ellipsize="end"/>
</LinearLayout>
- <ProgressBar
- android:id="@android:id/progress"
- style="?android:attr/progressBarStyleHorizontal"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:layout_marginTop="4dp"
- android:max="100"
- android:visibility="gone"/>
</LinearLayout>
+ <LinearLayout
+ android:id="@+id/radio_extra_widget_container"
+ android:layout_width="wrap_content"
+ android:layout_height="match_parent"
+ android:orientation="horizontal"
+ android:gravity="center_vertical">
+ <View
+ android:layout_width=".75dp"
+ android:layout_height="match_parent"
+ android:layout_marginTop="16dp"
+ android:layout_marginBottom="16dp"
+ android:background="?android:attr/dividerVertical" />
+ <ImageView
+ android:id="@+id/radio_extra_widget"
+ android:layout_width="wrap_content"
+ android:layout_height="fill_parent"
+ android:src="@drawable/ic_settings_accent"
+ android:contentDescription="@string/settings_label"
+ android:paddingStart="16dp"
+ android:paddingEnd="16dp"
+ android:layout_gravity="center"
+ android:background="?android:attr/selectableItemBackground" />
+ </LinearLayout>
</LinearLayout>
diff --git a/packages/SettingsLib/RadioButtonPreference/res/values/strings.xml b/packages/SettingsLib/RadioButtonPreference/res/values/strings.xml
new file mode 100644
index 0000000..ff3f90c
--- /dev/null
+++ b/packages/SettingsLib/RadioButtonPreference/res/values/strings.xml
@@ -0,0 +1,23 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Copyright (C) 2021 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.
+ -->
+
+<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+
+ <!-- Content description for RadioButton with extra gear icon [CHAR LIMIT=NONE] -->
+ <string name="settings_label">Settings</string>
+
+</resources>
\ No newline at end of file
diff --git a/packages/SettingsLib/RadioButtonPreference/src/com/android/settingslib/widget/RadioButtonPreference.java b/packages/SettingsLib/RadioButtonPreference/src/com/android/settingslib/widget/RadioButtonPreference.java
index 05e008c..f50127f 100644
--- a/packages/SettingsLib/RadioButtonPreference/src/com/android/settingslib/widget/RadioButtonPreference.java
+++ b/packages/SettingsLib/RadioButtonPreference/src/com/android/settingslib/widget/RadioButtonPreference.java
@@ -20,7 +20,7 @@
import android.text.TextUtils;
import android.util.AttributeSet;
import android.view.View;
-import android.widget.TextView;
+import android.widget.ImageView;
import androidx.preference.CheckBoxPreference;
import androidx.preference.PreferenceViewHolder;
@@ -34,6 +34,9 @@
* In other words, there's no "RadioButtonPreferenceGroup" in this
* implementation. When you check one RadioButtonPreference, if you want to
* uncheck all the other preferences, you should do that by code yourself.
+ *
+ * RadioButtonPreference can assign a extraWidgetListener to show a gear icon
+ * on the right side that can open another page.
*/
public class RadioButtonPreference extends CheckBoxPreference {
@@ -53,6 +56,10 @@
private View mAppendix;
private int mAppendixVisibility = -1;
+ private View mExtraWidgetContainer;
+ private ImageView mExtraWidget;
+
+ private View.OnClickListener mExtraWidgetOnClickListener;
/**
* Perform inflation from XML and apply a class-specific base style.
@@ -69,7 +76,6 @@
init();
}
-
/**
* Perform inflation from XML and apply a class-specific base style.
*
@@ -136,11 +142,10 @@
}
}
- TextView title = (TextView) holder.findViewById(android.R.id.title);
- if (title != null) {
- title.setSingleLine(false);
- title.setMaxLines(3);
- }
+ mExtraWidget = (ImageView) holder.findViewById(R.id.radio_extra_widget);
+ mExtraWidgetContainer = holder.findViewById(R.id.radio_extra_widget_container);
+
+ setExtraWidgetOnClickListener(mExtraWidgetOnClickListener);
}
/**
@@ -155,6 +160,24 @@
mAppendixVisibility = visibility;
}
+ /**
+ * Sets the callback to be invoked when extra widget is clicked by the user.
+ *
+ * @param listener The callback to be invoked
+ */
+ public void setExtraWidgetOnClickListener(View.OnClickListener listener) {
+ mExtraWidgetOnClickListener = listener;
+
+ if (mExtraWidget == null || mExtraWidgetContainer == null) {
+ return;
+ }
+
+ mExtraWidget.setOnClickListener(mExtraWidgetOnClickListener);
+
+ mExtraWidgetContainer.setVisibility((mExtraWidgetOnClickListener != null)
+ ? View.VISIBLE : View.GONE);
+ }
+
private void init() {
setWidgetLayoutResource(R.layout.preference_widget_radiobutton);
setLayoutResource(R.layout.preference_radio);
diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/widget/RadioButtonPreferenceTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/widget/RadioButtonPreferenceTest.java
index d58e68a..a5028ff 100644
--- a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/widget/RadioButtonPreferenceTest.java
+++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/widget/RadioButtonPreferenceTest.java
@@ -40,10 +40,30 @@
private Application mContext;
private RadioButtonPreference mPreference;
+ private View mExtraWidgetContainer;
+ private View mExtraWidget;
+
+ private boolean mIsClickListenerCalled;
+ private View.OnClickListener mClickListener = new View.OnClickListener() {
+ @Override
+ public void onClick(View v) {
+ mIsClickListenerCalled = true;
+ }
+ };
+
@Before
public void setUp() {
mContext = RuntimeEnvironment.application;
mPreference = new RadioButtonPreference(mContext);
+
+ View view = LayoutInflater.from(mContext)
+ .inflate(R.layout.preference_radio, null /* root */);
+ PreferenceViewHolder preferenceViewHolder =
+ PreferenceViewHolder.createInstanceForTests(view);
+ mPreference.onBindViewHolder(preferenceViewHolder);
+
+ mExtraWidgetContainer = view.findViewById(R.id.radio_extra_widget_container);
+ mExtraWidget = view.findViewById(R.id.radio_extra_widget);
}
@Test
@@ -57,26 +77,30 @@
}
@Test
- public void summary_containerShouldBeVisible() {
+ public void onBindViewHolder_withSummary_containerShouldBeVisible() {
mPreference.setSummary("some summary");
View summaryContainer = new View(mContext);
View view = mock(View.class);
when(view.findViewById(R.id.summary_container)).thenReturn(summaryContainer);
PreferenceViewHolder preferenceViewHolder =
PreferenceViewHolder.createInstanceForTests(view);
+
mPreference.onBindViewHolder(preferenceViewHolder);
+
assertEquals(View.VISIBLE, summaryContainer.getVisibility());
}
@Test
- public void emptySummary_containerShouldBeGone() {
+ public void onBindViewHolder_emptySummary_containerShouldBeGone() {
mPreference.setSummary("");
View summaryContainer = new View(mContext);
View view = mock(View.class);
when(view.findViewById(R.id.summary_container)).thenReturn(summaryContainer);
PreferenceViewHolder preferenceViewHolder =
PreferenceViewHolder.createInstanceForTests(view);
+
mPreference.onBindViewHolder(preferenceViewHolder);
+
assertEquals(View.GONE, summaryContainer.getVisibility());
}
@@ -93,11 +117,36 @@
}
@Test
- public void hideAppendix_shouldBeGone() {
+ public void setAppendixVisibility_setGone_shouldBeGone() {
mPreference.setAppendixVisibility(View.GONE);
- View view = LayoutInflater.from(mContext).inflate(R.layout.preference_radio, null);
+
+ View view = LayoutInflater.from(mContext)
+ .inflate(R.layout.preference_radio, null /* root */);
PreferenceViewHolder holder = PreferenceViewHolder.createInstanceForTests(view);
mPreference.onBindViewHolder(holder);
assertThat(holder.findViewById(R.id.appendix).getVisibility()).isEqualTo(View.GONE);
}
+
+ @Test
+ public void setExtraWidgetListener_setNull_extraWidgetShouldInvisible() {
+ mPreference.setExtraWidgetOnClickListener(null);
+
+ assertEquals(View.GONE, mExtraWidgetContainer.getVisibility());
+ }
+
+ @Test
+ public void setExtraWidgetListener_extraWidgetShouldVisible() {
+ mPreference.setExtraWidgetOnClickListener(mClickListener);
+
+ assertEquals(View.VISIBLE, mExtraWidgetContainer.getVisibility());
+ }
+
+ @Test
+ public void onClickListener_setExtraWidgetOnClickListener_ShouldCalled() {
+ mPreference.setExtraWidgetOnClickListener(mClickListener);
+
+ assertThat(mIsClickListenerCalled).isFalse();
+ mExtraWidget.callOnClick();
+ assertThat(mIsClickListenerCalled).isTrue();
+ }
}
diff --git a/packages/Shell/AndroidManifest.xml b/packages/Shell/AndroidManifest.xml
index 7ea9686..a184cd7 100644
--- a/packages/Shell/AndroidManifest.xml
+++ b/packages/Shell/AndroidManifest.xml
@@ -298,6 +298,9 @@
<uses-permission android:name="android.permission.UPGRADE_RUNTIME_PERMISSIONS" />
<!-- Permission needed to read wifi network credentials for CtsNetTestCases -->
+ <uses-permission android:name="android.permission.NETWORK_AIRPLANE_MODE" />
+
+ <!-- Permission needed to read wifi network credentials for CtsNetTestCases -->
<uses-permission android:name="android.permission.READ_WIFI_CREDENTIAL" />
<!-- Permission needed to use wifi usability API's for CtsNetTestCases -->
diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/system/ActivityOptionsCompat.java b/packages/SystemUI/shared/src/com/android/systemui/shared/system/ActivityOptionsCompat.java
index 1a71f11..d672c2c 100644
--- a/packages/SystemUI/shared/src/com/android/systemui/shared/system/ActivityOptionsCompat.java
+++ b/packages/SystemUI/shared/src/com/android/systemui/shared/system/ActivityOptionsCompat.java
@@ -16,8 +16,6 @@
package com.android.systemui.shared.system;
-import static android.app.ActivityTaskManager.SPLIT_SCREEN_CREATE_MODE_BOTTOM_OR_RIGHT;
-import static android.app.ActivityTaskManager.SPLIT_SCREEN_CREATE_MODE_TOP_OR_LEFT;
import static android.app.WindowConfiguration.WINDOWING_MODE_FREEFORM;
import static android.app.WindowConfiguration.WINDOWING_MODE_SPLIT_SCREEN_PRIMARY;
import static android.app.WindowConfiguration.WINDOWING_MODE_SPLIT_SCREEN_SECONDARY;
@@ -48,9 +46,6 @@
options.setLaunchWindowingMode(isPrimary
? WINDOWING_MODE_SPLIT_SCREEN_PRIMARY
: WINDOWING_MODE_SPLIT_SCREEN_SECONDARY);
- options.setSplitScreenCreateMode(dockTopLeft
- ? SPLIT_SCREEN_CREATE_MODE_TOP_OR_LEFT
- : SPLIT_SCREEN_CREATE_MODE_BOTTOM_OR_RIGHT);
return options;
}
diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/system/LatencyTrackerCompat.java b/packages/SystemUI/shared/src/com/android/systemui/shared/system/LatencyTrackerCompat.java
index bf4fb0b..a8c19ec 100644
--- a/packages/SystemUI/shared/src/com/android/systemui/shared/system/LatencyTrackerCompat.java
+++ b/packages/SystemUI/shared/src/com/android/systemui/shared/system/LatencyTrackerCompat.java
@@ -24,10 +24,6 @@
* @see LatencyTracker
*/
public class LatencyTrackerCompat {
- public static boolean isEnabled(Context context) {
- return LatencyTracker.isEnabled(context);
- }
-
/**
* @see LatencyTracker
* @deprecated Please use {@link LatencyTrackerCompat#logToggleRecents(Context, int)} instead.
diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/system/ViewTreeObserverWrapper.java b/packages/SystemUI/shared/src/com/android/systemui/shared/system/ViewTreeObserverWrapper.java
index 4a870f1..cfb23f9 100644
--- a/packages/SystemUI/shared/src/com/android/systemui/shared/system/ViewTreeObserverWrapper.java
+++ b/packages/SystemUI/shared/src/com/android/systemui/shared/system/ViewTreeObserverWrapper.java
@@ -16,6 +16,7 @@
package com.android.systemui.shared.system;
+import android.annotation.NonNull;
import android.annotation.Nullable;
import android.graphics.Rect;
import android.graphics.Region;
@@ -26,18 +27,21 @@
public class ViewTreeObserverWrapper {
+ private static final HashMap<OnComputeInsetsListener, ViewTreeObserver>
+ sListenerObserverMap = new HashMap<>();
private static final HashMap<OnComputeInsetsListener, OnComputeInternalInsetsListener>
- sOnComputeInsetsListenerMap = new HashMap<>();
+ sListenerInternalListenerMap = new HashMap<>();
/**
- * Register a callback to be invoked when the invoked when it is time to
- * compute the window's insets.
+ * Register a callback to be invoked when the invoked when it is time to compute the window's
+ * insets.
*
+ * @param observer The observer to be added
* @param listener The callback to add
* @throws IllegalStateException If {@link ViewTreeObserver#isAlive()} returns false
*/
public static void addOnComputeInsetsListener(
- ViewTreeObserver observer, OnComputeInsetsListener listener) {
+ @NonNull ViewTreeObserver observer, @NonNull OnComputeInsetsListener listener) {
final OnComputeInternalInsetsListener internalListener = internalInOutInfo -> {
final InsetsInfo inOutInfo = new InsetsInfo();
inOutInfo.contentInsets.set(internalInOutInfo.contentInsets);
@@ -49,23 +53,26 @@
internalInOutInfo.touchableRegion.set(inOutInfo.touchableRegion);
internalInOutInfo.setTouchableInsets(inOutInfo.mTouchableInsets);
};
- sOnComputeInsetsListenerMap.put(listener, internalListener);
+ sListenerObserverMap.put(listener, observer);
+ sListenerInternalListenerMap.put(listener, internalListener);
observer.addOnComputeInternalInsetsListener(internalListener);
}
/**
- * Remove a previously installed insets computation callback
+ * Remove a previously installed insets computation callback.
*
* @param victim The callback to remove
* @throws IllegalStateException If {@link ViewTreeObserver#isAlive()} returns false
* @see #addOnComputeInsetsListener(ViewTreeObserver, OnComputeInsetsListener)
*/
- public void removeOnComputeInsetsListener(
- ViewTreeObserver observer, OnComputeInsetsListener victim) {
- final OnComputeInternalInsetsListener listener = sOnComputeInsetsListenerMap.get(victim);
- if (listener != null) {
+ public static void removeOnComputeInsetsListener(@NonNull OnComputeInsetsListener victim) {
+ final ViewTreeObserver observer = sListenerObserverMap.get(victim);
+ final OnComputeInternalInsetsListener listener = sListenerInternalListenerMap.get(victim);
+ if (observer != null && listener != null) {
observer.removeOnComputeInternalInsetsListener(listener);
}
+ sListenerObserverMap.remove(victim);
+ sListenerInternalListenerMap.remove(victim);
}
/**
diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/system/WindowManagerWrapper.java b/packages/SystemUI/shared/src/com/android/systemui/shared/system/WindowManagerWrapper.java
index d3066b4..b38270c 100644
--- a/packages/SystemUI/shared/src/com/android/systemui/shared/system/WindowManagerWrapper.java
+++ b/packages/SystemUI/shared/src/com/android/systemui/shared/system/WindowManagerWrapper.java
@@ -83,6 +83,11 @@
public static final int WINDOWING_MODE_FREEFORM = WindowConfiguration.WINDOWING_MODE_FREEFORM;
public static final int ITYPE_EXTRA_NAVIGATION_BAR = InsetsState.ITYPE_EXTRA_NAVIGATION_BAR;
+ public static final int ITYPE_LEFT_TAPPABLE_ELEMENT = InsetsState.ITYPE_LEFT_TAPPABLE_ELEMENT;
+ public static final int ITYPE_TOP_TAPPABLE_ELEMENT = InsetsState.ITYPE_TOP_TAPPABLE_ELEMENT;
+ public static final int ITYPE_RIGHT_TAPPABLE_ELEMENT = InsetsState.ITYPE_RIGHT_TAPPABLE_ELEMENT;
+ public static final int ITYPE_BOTTOM_TAPPABLE_ELEMENT =
+ InsetsState.ITYPE_BOTTOM_TAPPABLE_ELEMENT;
private static final WindowManagerWrapper sInstance = new WindowManagerWrapper();
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardInputView.java b/packages/SystemUI/src/com/android/keyguard/KeyguardInputView.java
index d58b95c..d1494df 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardInputView.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardInputView.java
@@ -23,10 +23,16 @@
import androidx.annotation.Nullable;
+import com.android.systemui.Gefingerpoken;
+
+import java.util.ArrayList;
+import java.util.List;
+
/**
* A Base class for all Keyguard password/pattern/pin related inputs.
*/
public abstract class KeyguardInputView extends LinearLayout {
+ private final List<Gefingerpoken> mMotionEventListener = new ArrayList<>();
public KeyguardInputView(Context context) {
super(context);
@@ -56,4 +62,25 @@
boolean startDisappearAnimation(Runnable finishRunnable) {
return false;
}
+
+ void addMotionEventListener(Gefingerpoken listener) {
+ mMotionEventListener.add(listener);
+ }
+
+ void removeMotionEventListener(Gefingerpoken listener) {
+ mMotionEventListener.remove(listener);
+ }
+
+ @Override
+ public boolean onTouchEvent(MotionEvent event) {
+ return mMotionEventListener.stream().anyMatch(listener -> listener.onTouchEvent(event))
+ || super.onTouchEvent(event);
+ }
+
+ @Override
+ public boolean onInterceptTouchEvent(MotionEvent event) {
+ return mMotionEventListener.stream().anyMatch(
+ listener -> listener.onInterceptTouchEvent(event))
+ || super.onInterceptTouchEvent(event);
+ }
}
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardInputViewController.java b/packages/SystemUI/src/com/android/keyguard/KeyguardInputViewController.java
index 6aa5e0d..1c691e7 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardInputViewController.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardInputViewController.java
@@ -26,6 +26,7 @@
import com.android.internal.widget.LockPatternUtils;
import com.android.keyguard.KeyguardSecurityModel.SecurityMode;
import com.android.systemui.R;
+import com.android.systemui.classifier.FalsingCollector;
import com.android.systemui.dagger.qualifiers.Main;
import com.android.systemui.util.ViewController;
import com.android.systemui.util.concurrency.DelayableExecutor;
@@ -155,6 +156,7 @@
private final Resources mResources;
private LiftToActivateListener mLiftToActivateListener;
private TelephonyManager mTelephonyManager;
+ private final FalsingCollector mFalsingCollector;
@Inject
public Factory(KeyguardUpdateMonitor keyguardUpdateMonitor,
@@ -163,7 +165,7 @@
KeyguardMessageAreaController.Factory messageAreaControllerFactory,
InputMethodManager inputMethodManager, @Main DelayableExecutor mainExecutor,
@Main Resources resources, LiftToActivateListener liftToActivateListener,
- TelephonyManager telephonyManager) {
+ TelephonyManager telephonyManager, FalsingCollector falsingCollector) {
mKeyguardUpdateMonitor = keyguardUpdateMonitor;
mLockPatternUtils = lockPatternUtils;
mLatencyTracker = latencyTracker;
@@ -173,6 +175,7 @@
mResources = resources;
mLiftToActivateListener = liftToActivateListener;
mTelephonyManager = telephonyManager;
+ mFalsingCollector = falsingCollector;
}
/** Create a new {@link KeyguardInputViewController}. */
@@ -191,17 +194,17 @@
return new KeyguardPinViewController((KeyguardPINView) keyguardInputView,
mKeyguardUpdateMonitor, securityMode, mLockPatternUtils,
keyguardSecurityCallback, mMessageAreaControllerFactory, mLatencyTracker,
- mLiftToActivateListener);
+ mLiftToActivateListener, mFalsingCollector);
} else if (keyguardInputView instanceof KeyguardSimPinView) {
return new KeyguardSimPinViewController((KeyguardSimPinView) keyguardInputView,
mKeyguardUpdateMonitor, securityMode, mLockPatternUtils,
keyguardSecurityCallback, mMessageAreaControllerFactory, mLatencyTracker,
- mLiftToActivateListener, mTelephonyManager);
+ mLiftToActivateListener, mTelephonyManager, mFalsingCollector);
} else if (keyguardInputView instanceof KeyguardSimPukView) {
return new KeyguardSimPukViewController((KeyguardSimPukView) keyguardInputView,
mKeyguardUpdateMonitor, securityMode, mLockPatternUtils,
keyguardSecurityCallback, mMessageAreaControllerFactory, mLatencyTracker,
- mLiftToActivateListener, mTelephonyManager);
+ mLiftToActivateListener, mTelephonyManager, mFalsingCollector);
}
throw new RuntimeException("Unable to find controller for " + keyguardInputView);
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardPinBasedInputViewController.java b/packages/SystemUI/src/com/android/keyguard/KeyguardPinBasedInputViewController.java
index 4d0ebff..f247948 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardPinBasedInputViewController.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardPinBasedInputViewController.java
@@ -25,12 +25,15 @@
import com.android.internal.util.LatencyTracker;
import com.android.internal.widget.LockPatternUtils;
import com.android.keyguard.KeyguardSecurityModel.SecurityMode;
+import com.android.systemui.Gefingerpoken;
import com.android.systemui.R;
+import com.android.systemui.classifier.FalsingCollector;
public abstract class KeyguardPinBasedInputViewController<T extends KeyguardPinBasedInputView>
extends KeyguardAbsKeyInputViewController<T> {
private final LiftToActivateListener mLiftToActivateListener;
+ private final FalsingCollector mFalsingCollector;
protected PasswordTextView mPasswordEntry;
private final OnKeyListener mOnKeyListener = (v, keyCode, event) -> {
@@ -40,13 +43,26 @@
return false;
};
- private final OnTouchListener mOnTouchListener = (v, event) -> {
+ private final OnTouchListener mActionButtonTouchListener = (v, event) -> {
if (event.getActionMasked() == MotionEvent.ACTION_DOWN) {
mView.doHapticKeyClick();
}
return false;
};
+ private final Gefingerpoken mGlobalTouchListener = new Gefingerpoken() {
+ @Override
+ public boolean onInterceptTouchEvent(MotionEvent ev) {
+ mFalsingCollector.avoidGesture();
+ return false;
+ }
+
+ @Override
+ public boolean onTouchEvent(MotionEvent ev) {
+ return false;
+ }
+ };
+
protected KeyguardPinBasedInputViewController(T view,
KeyguardUpdateMonitor keyguardUpdateMonitor,
SecurityMode securityMode,
@@ -54,10 +70,12 @@
KeyguardSecurityCallback keyguardSecurityCallback,
KeyguardMessageAreaController.Factory messageAreaControllerFactory,
LatencyTracker latencyTracker,
- LiftToActivateListener liftToActivateListener) {
+ LiftToActivateListener liftToActivateListener,
+ FalsingCollector falsingCollector) {
super(view, keyguardUpdateMonitor, securityMode, lockPatternUtils, keyguardSecurityCallback,
messageAreaControllerFactory, latencyTracker);
mLiftToActivateListener = liftToActivateListener;
+ mFalsingCollector = falsingCollector;
mPasswordEntry = mView.findViewById(mView.getPasswordTextViewId());
}
@@ -65,11 +83,13 @@
protected void onViewAttached() {
super.onViewAttached();
+ mView.addMotionEventListener(mGlobalTouchListener);
+
mPasswordEntry.setOnKeyListener(mOnKeyListener);
mPasswordEntry.setUserActivityListener(this::onUserInput);
View deleteButton = mView.findViewById(R.id.delete_button);
- deleteButton.setOnTouchListener(mOnTouchListener);
+ deleteButton.setOnTouchListener(mActionButtonTouchListener);
deleteButton.setOnClickListener(v -> {
// check for time-based lockouts
if (mPasswordEntry.isEnabled()) {
@@ -87,7 +107,7 @@
View okButton = mView.findViewById(R.id.key_enter);
if (okButton != null) {
- okButton.setOnTouchListener(mOnTouchListener);
+ okButton.setOnTouchListener(mActionButtonTouchListener);
okButton.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
@@ -101,6 +121,12 @@
}
@Override
+ protected void onViewDetached() {
+ super.onViewDetached();
+ mView.removeMotionEventListener(mGlobalTouchListener);
+ }
+
+ @Override
public void onResume(int reason) {
super.onResume(reason);
mPasswordEntry.requestFocus();
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardPinViewController.java b/packages/SystemUI/src/com/android/keyguard/KeyguardPinViewController.java
index fb0d6be..c0aa2af 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardPinViewController.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardPinViewController.java
@@ -22,6 +22,7 @@
import com.android.internal.widget.LockPatternUtils;
import com.android.keyguard.KeyguardSecurityModel.SecurityMode;
import com.android.systemui.R;
+import com.android.systemui.classifier.FalsingCollector;
public class KeyguardPinViewController
extends KeyguardPinBasedInputViewController<KeyguardPINView> {
@@ -32,10 +33,11 @@
SecurityMode securityMode, LockPatternUtils lockPatternUtils,
KeyguardSecurityCallback keyguardSecurityCallback,
KeyguardMessageAreaController.Factory messageAreaControllerFactory,
- LatencyTracker latencyTracker,
- LiftToActivateListener liftToActivateListener) {
+ LatencyTracker latencyTracker, LiftToActivateListener liftToActivateListener,
+ FalsingCollector falsingCollector) {
super(view, keyguardUpdateMonitor, securityMode, lockPatternUtils, keyguardSecurityCallback,
- messageAreaControllerFactory, latencyTracker, liftToActivateListener);
+ messageAreaControllerFactory, latencyTracker, liftToActivateListener,
+ falsingCollector);
mKeyguardUpdateMonitor = keyguardUpdateMonitor;
}
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardSimPinViewController.java b/packages/SystemUI/src/com/android/keyguard/KeyguardSimPinViewController.java
index 5b4a7ff..b218141 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardSimPinViewController.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardSimPinViewController.java
@@ -38,6 +38,7 @@
import com.android.internal.widget.LockPatternUtils;
import com.android.keyguard.KeyguardSecurityModel.SecurityMode;
import com.android.systemui.R;
+import com.android.systemui.classifier.FalsingCollector;
public class KeyguardSimPinViewController
extends KeyguardPinBasedInputViewController<KeyguardSimPinView> {
@@ -76,11 +77,11 @@
SecurityMode securityMode, LockPatternUtils lockPatternUtils,
KeyguardSecurityCallback keyguardSecurityCallback,
KeyguardMessageAreaController.Factory messageAreaControllerFactory,
- LatencyTracker latencyTracker,
- LiftToActivateListener liftToActivateListener,
- TelephonyManager telephonyManager) {
+ LatencyTracker latencyTracker, LiftToActivateListener liftToActivateListener,
+ TelephonyManager telephonyManager, FalsingCollector falsingCollector) {
super(view, keyguardUpdateMonitor, securityMode, lockPatternUtils, keyguardSecurityCallback,
- messageAreaControllerFactory, latencyTracker, liftToActivateListener);
+ messageAreaControllerFactory, latencyTracker, liftToActivateListener,
+ falsingCollector);
mKeyguardUpdateMonitor = keyguardUpdateMonitor;
mTelephonyManager = telephonyManager;
mSimImageView = mView.findViewById(R.id.keyguard_sim);
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardSimPukViewController.java b/packages/SystemUI/src/com/android/keyguard/KeyguardSimPukViewController.java
index eafb33f..890a17c 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardSimPukViewController.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardSimPukViewController.java
@@ -39,6 +39,7 @@
import com.android.keyguard.KeyguardSecurityModel.SecurityMode;
import com.android.systemui.Dependency;
import com.android.systemui.R;
+import com.android.systemui.classifier.FalsingCollector;
public class KeyguardSimPukViewController
extends KeyguardPinBasedInputViewController<KeyguardSimPukView> {
@@ -83,11 +84,11 @@
SecurityMode securityMode, LockPatternUtils lockPatternUtils,
KeyguardSecurityCallback keyguardSecurityCallback,
KeyguardMessageAreaController.Factory messageAreaControllerFactory,
- LatencyTracker latencyTracker,
- LiftToActivateListener liftToActivateListener,
- TelephonyManager telephonyManager) {
+ LatencyTracker latencyTracker, LiftToActivateListener liftToActivateListener,
+ TelephonyManager telephonyManager, FalsingCollector falsingCollector) {
super(view, keyguardUpdateMonitor, securityMode, lockPatternUtils, keyguardSecurityCallback,
- messageAreaControllerFactory, latencyTracker, liftToActivateListener);
+ messageAreaControllerFactory, latencyTracker, liftToActivateListener,
+ falsingCollector);
mKeyguardUpdateMonitor = keyguardUpdateMonitor;
mTelephonyManager = telephonyManager;
mSimImageView = mView.findViewById(R.id.keyguard_sim);
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardSliceView.java b/packages/SystemUI/src/com/android/keyguard/KeyguardSliceView.java
index 3cbab8e..fb97a30 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardSliceView.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardSliceView.java
@@ -26,6 +26,7 @@
import android.content.res.Resources;
import android.graphics.Color;
import android.graphics.drawable.Drawable;
+import android.graphics.drawable.InsetDrawable;
import android.graphics.text.LineBreaker;
import android.net.Uri;
import android.os.Trace;
@@ -239,6 +240,12 @@
final int iconSize = mHasHeader ? mIconSizeWithHeader : mIconSize;
iconDrawable = icon.getIcon().loadDrawable(mContext);
if (iconDrawable != null) {
+ if ((iconDrawable instanceof InsetDrawable)
+ && mLockScreenMode == KeyguardUpdateMonitor.LOCK_SCREEN_MODE_LAYOUT_1) {
+ // System icons (DnD) use insets which are fine for centered slice content
+ // but will cause a slight indent for left/right-aligned slice views
+ iconDrawable = ((InsetDrawable) iconDrawable).getDrawable();
+ }
final int width = (int) (iconDrawable.getIntrinsicWidth()
/ (float) iconDrawable.getIntrinsicHeight() * iconSize);
iconDrawable.setBounds(0, 0, Math.max(width, 1), iconSize);
diff --git a/packages/SystemUI/src/com/android/systemui/accessibility/MagnificationGestureDetector.java b/packages/SystemUI/src/com/android/systemui/accessibility/MagnificationGestureDetector.java
new file mode 100644
index 0000000..4c892e29
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/accessibility/MagnificationGestureDetector.java
@@ -0,0 +1,195 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.accessibility;
+
+import android.annotation.DisplayContext;
+import android.annotation.NonNull;
+import android.content.Context;
+import android.graphics.PointF;
+import android.os.Handler;
+import android.view.Display;
+import android.view.MotionEvent;
+import android.view.ViewConfiguration;
+
+/**
+ * Detects single tap and drag gestures using the supplied {@link MotionEvent}s. The {@link
+ * OnGestureListener} callback will notify users when a particular motion event has occurred. This
+ * class should only be used with {@link MotionEvent}s reported via touch (don't use for trackball
+ * events).
+ */
+class MagnificationGestureDetector {
+
+ interface OnGestureListener {
+ /**
+ * Called when a tap is completed within {@link ViewConfiguration#getLongPressTimeout()} and
+ * the offset between {@link MotionEvent}s and the down event doesn't exceed {@link
+ * ViewConfiguration#getScaledTouchSlop()}.
+ *
+ * @return {@code true} if this gesture is handled.
+ */
+ boolean onSingleTap();
+
+ /**
+ * Called when the user is performing dragging gesture. It is started after the offset
+ * between the down location and the move event location exceed
+ * {@link ViewConfiguration#getScaledTouchSlop()}.
+ *
+ * @param offsetX The X offset in screen coordinate.
+ * @param offsetY The Y offset in screen coordinate.
+ * @return {@code true} if this gesture is handled.
+ */
+ boolean onDrag(float offsetX, float offsetY);
+
+ /**
+ * Notified when a tap occurs with the down {@link MotionEvent} that triggered it. This will
+ * be triggered immediately for every down event. All other events should be preceded by
+ * this.
+ *
+ * @param x The X coordinate of the down event.
+ * @param y The Y coordinate of the down event.
+ * @return {@code true} if the down event is handled, otherwise the events won't be sent to
+ * the view.
+ */
+ boolean onStart(float x, float y);
+
+ /**
+ * Called when the detection is finished. In other words, it is called when up/cancel {@link
+ * MotionEvent} is received. It will be triggered after single-tap
+ *
+ * @param x The X coordinate on the screen of the up event or the cancel event.
+ * @param y The Y coordinate on the screen of the up event or the cancel event.
+ * @return {@code true} if the event is handled.
+ */
+ boolean onFinish(float x, float y);
+ }
+
+ private final PointF mPointerDown = new PointF();
+ private final PointF mPointerLocation = new PointF(Float.NaN, Float.NaN);
+ private final Handler mHandler;
+ private final Runnable mCancelTapGestureRunnable;
+ private final OnGestureListener mOnGestureListener;
+ private int mTouchSlopSquare;
+ // Assume the gesture default is a single-tap. Set it to false if the gesture couldn't be a
+ // single-tap anymore.
+ private boolean mDetectSingleTap = true;
+ private boolean mDraggingDetected = false;
+
+ /**
+ * @param context {@link Context} that is from {@link Context#createDisplayContext(Display)}.
+ * @param handler The handler to post the runnable.
+ * @param listener The listener invoked for all the callbacks.
+ */
+ MagnificationGestureDetector(@DisplayContext Context context, @NonNull Handler handler,
+ @NonNull OnGestureListener listener) {
+ final int touchSlop = ViewConfiguration.get(context).getScaledTouchSlop();
+ mTouchSlopSquare = touchSlop * touchSlop;
+ mHandler = handler;
+ mOnGestureListener = listener;
+ mCancelTapGestureRunnable = () -> mDetectSingleTap = false;
+ }
+
+ /**
+ * Analyzes the given motion event and if applicable to trigger the appropriate callbacks on the
+ * {@link OnGestureListener} supplied.
+ *
+ * @param event The current motion event.
+ * @return {@code True} if the {@link OnGestureListener} consumes the event, else false.
+ */
+ boolean onTouch(MotionEvent event) {
+ final float rawX = event.getRawX();
+ final float rawY = event.getRawY();
+ boolean handled = false;
+ switch (event.getAction()) {
+ case MotionEvent.ACTION_DOWN:
+ mPointerDown.set(rawX, rawY);
+ mHandler.postAtTime(mCancelTapGestureRunnable,
+ event.getDownTime() + ViewConfiguration.getLongPressTimeout());
+ handled |= mOnGestureListener.onStart(rawX, rawY);
+ break;
+ case MotionEvent.ACTION_POINTER_DOWN:
+ stopSingleTapDetection();
+ break;
+ case MotionEvent.ACTION_MOVE:
+ stopSingleTapDetectionIfNeeded(rawX, rawY);
+ handled |= notifyDraggingGestureIfNeeded(rawX, rawY);
+ break;
+ case MotionEvent.ACTION_UP:
+ stopSingleTapDetectionIfNeeded(rawX, rawY);
+ if (mDetectSingleTap) {
+ handled |= mOnGestureListener.onSingleTap();
+ }
+ // Fall through
+ case MotionEvent.ACTION_CANCEL:
+ handled |= mOnGestureListener.onFinish(rawX, rawY);
+ reset();
+ break;
+ }
+ return handled;
+ }
+
+ private void stopSingleTapDetectionIfNeeded(float x, float y) {
+ if (mDraggingDetected) {
+ return;
+ }
+ if (!isLocationValid(mPointerDown)) {
+ return;
+ }
+
+ final int deltaX = (int) (mPointerDown.x - x);
+ final int deltaY = (int) (mPointerDown.y - y);
+ final int distanceSquare = (deltaX * deltaX) + (deltaY * deltaY);
+ if (distanceSquare > mTouchSlopSquare) {
+ mDraggingDetected = true;
+ stopSingleTapDetection();
+ }
+ }
+
+ private void stopSingleTapDetection() {
+ mHandler.removeCallbacks(mCancelTapGestureRunnable);
+ mDetectSingleTap = false;
+ }
+
+ private boolean notifyDraggingGestureIfNeeded(float x, float y) {
+ if (!mDraggingDetected) {
+ return false;
+ }
+ if (!isLocationValid(mPointerLocation)) {
+ mPointerLocation.set(mPointerDown);
+ }
+ final float offsetX = x - mPointerLocation.x;
+ final float offsetY = y - mPointerLocation.y;
+ mPointerLocation.set(x, y);
+ return mOnGestureListener.onDrag(offsetX, offsetY);
+ }
+
+ private void reset() {
+ resetPointF(mPointerDown);
+ resetPointF(mPointerLocation);
+ mHandler.removeCallbacks(mCancelTapGestureRunnable);
+ mDetectSingleTap = true;
+ mDraggingDetected = false;
+ }
+
+ private static void resetPointF(PointF pointF) {
+ pointF.x = Float.NaN;
+ pointF.y = Float.NaN;
+ }
+
+ private static boolean isLocationValid(PointF location) {
+ return !Float.isNaN(location.x) && !Float.isNaN(location.y);
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/accessibility/MagnificationModeSwitch.java b/packages/SystemUI/src/com/android/systemui/accessibility/MagnificationModeSwitch.java
index edc3216..c1cf8d3 100644
--- a/packages/SystemUI/src/com/android/systemui/accessibility/MagnificationModeSwitch.java
+++ b/packages/SystemUI/src/com/android/systemui/accessibility/MagnificationModeSwitch.java
@@ -22,16 +22,13 @@
import android.content.Context;
import android.content.pm.ActivityInfo;
import android.graphics.PixelFormat;
-import android.graphics.PointF;
import android.graphics.Rect;
import android.os.Bundle;
import android.os.UserHandle;
import android.provider.Settings;
-import android.util.MathUtils;
import android.view.Gravity;
import android.view.MotionEvent;
import android.view.View;
-import android.view.ViewConfiguration;
import android.view.WindowManager;
import android.view.WindowManager.LayoutParams;
import android.view.accessibility.AccessibilityManager;
@@ -46,11 +43,11 @@
/**
* Shows/hides a {@link android.widget.ImageView} on the screen and changes the values of
- * {@link Settings.Secure.ACCESSIBILITY_MAGNIFICATION_MODE} when the UI is toggled.
+ * {@link Settings.Secure#ACCESSIBILITY_MAGNIFICATION_MODE} when the UI is toggled.
* The button icon is movable by dragging. And the button UI would automatically be dismissed after
* displaying for a period of time.
*/
-class MagnificationModeSwitch {
+class MagnificationModeSwitch implements MagnificationGestureDetector.OnGestureListener {
@VisibleForTesting
static final long FADING_ANIMATION_DURATION_MS = 300;
@@ -66,13 +63,11 @@
private final AccessibilityManager mAccessibilityManager;
private final WindowManager mWindowManager;
private final ImageView mImageView;
- private final PointF mLastDown = new PointF();
- private final PointF mLastDrag = new PointF();
- private final int mTapTimeout = ViewConfiguration.getTapTimeout();
- private final int mTouchSlop;
private int mMagnificationMode = Settings.Secure.ACCESSIBILITY_MAGNIFICATION_MODE_FULLSCREEN;
private final LayoutParams mParams;
private boolean mIsVisible = false;
+ private final MagnificationGestureDetector mGestureDetector;
+ private boolean mSingleTapDetected = false;
MagnificationModeSwitch(Context context) {
this(context, createView(context));
@@ -86,7 +81,6 @@
Context.WINDOW_SERVICE);
mParams = createLayoutParams(context);
mImageView = imageView;
- mTouchSlop = ViewConfiguration.get(mContext).getScaledTouchSlop();
applyResourcesValues();
mImageView.setOnTouchListener(this::onTouch);
mImageView.setAccessibilityDelegate(new View.AccessibilityDelegate() {
@@ -127,6 +121,8 @@
.start();
mIsFadeOutAnimating = true;
};
+ mGestureDetector = new MagnificationGestureDetector(context,
+ context.getMainThreadHandler(), this);
}
private CharSequence formatStateDescription() {
@@ -144,39 +140,38 @@
}
private boolean onTouch(View v, MotionEvent event) {
- if (!mIsVisible || mImageView == null) {
+ if (!mIsVisible) {
return false;
}
- switch (event.getAction()) {
- case MotionEvent.ACTION_DOWN:
- stopFadeOutAnimation();
- mLastDown.set(event.getRawX(), event.getRawY());
- mLastDrag.set(event.getRawX(), event.getRawY());
- return true;
- case MotionEvent.ACTION_MOVE:
- // Move the button position.
- moveButton(event.getRawX() - mLastDrag.x,
- event.getRawY() - mLastDrag.y);
- mLastDrag.set(event.getRawX(), event.getRawY());
- return true;
- case MotionEvent.ACTION_UP:
- // Single tap to toggle magnification mode and the button position will be reset
- // after the action is performed.
- final float distance = MathUtils.dist(mLastDown.x, mLastDown.y,
- event.getRawX(), event.getRawY());
- if ((event.getEventTime() - event.getDownTime()) <= mTapTimeout
- && distance <= mTouchSlop) {
- handleSingleTap();
- } else {
- showButton(mMagnificationMode);
- }
- return true;
- case MotionEvent.ACTION_CANCEL:
- showButton(mMagnificationMode);
- return true;
- default:
- return false;
+ return mGestureDetector.onTouch(event);
+ }
+
+ @Override
+ public boolean onSingleTap() {
+ mSingleTapDetected = true;
+ handleSingleTap();
+ return true;
+ }
+
+ @Override
+ public boolean onDrag(float offsetX, float offsetY) {
+ moveButton(offsetX, offsetY);
+ return true;
+ }
+
+ @Override
+ public boolean onStart(float x, float y) {
+ stopFadeOutAnimation();
+ return true;
+ }
+
+ @Override
+ public boolean onFinish(float xOffset, float yOffset) {
+ if (!mSingleTapDetected) {
+ showButton(mMagnificationMode);
}
+ mSingleTapDetected = false;
+ return true;
}
private void moveButton(float offsetX, float offsetY) {
diff --git a/packages/SystemUI/src/com/android/systemui/accessibility/WindowMagnificationController.java b/packages/SystemUI/src/com/android/systemui/accessibility/WindowMagnificationController.java
index 87dc6a5..3f7d2d8 100644
--- a/packages/SystemUI/src/com/android/systemui/accessibility/WindowMagnificationController.java
+++ b/packages/SystemUI/src/com/android/systemui/accessibility/WindowMagnificationController.java
@@ -20,6 +20,8 @@
import static android.view.WindowManagerPolicyConstants.NAV_BAR_MODE_2BUTTON;
import static android.view.WindowManagerPolicyConstants.NAV_BAR_MODE_GESTURAL;
+import android.animation.ObjectAnimator;
+import android.animation.PropertyValuesHolder;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.content.Context;
@@ -28,7 +30,6 @@
import android.graphics.Matrix;
import android.graphics.PixelFormat;
import android.graphics.Point;
-import android.graphics.PointF;
import android.graphics.Rect;
import android.graphics.RectF;
import android.graphics.Region;
@@ -66,7 +67,7 @@
* Class to handle adding and removing a window magnification.
*/
class WindowMagnificationController implements View.OnTouchListener, SurfaceHolder.Callback,
- MirrorWindowControl.MirrorWindowDelegate {
+ MirrorWindowControl.MirrorWindowDelegate, MagnificationGestureDetector.OnGestureListener {
private static final String TAG = "WindowMagnificationController";
// Delay to avoid updating state description too frequently.
@@ -74,6 +75,7 @@
// It should be consistent with the value defined in WindowMagnificationGestureHandler.
private static final Range<Float> A11Y_ACTION_SCALE_RANGE = new Range<>(2.0f, 8.0f);
private static final float A11Y_CHANGE_SCALE_DIFFERENCE = 1.0f;
+ private static final float ANIMATION_BOUNCE_EFFECT_SCALE = 1.05f;
private final Context mContext;
private final Resources mResources;
private final Handler mHandler;
@@ -102,7 +104,6 @@
private View mRightDrag;
private View mBottomDrag;
- private final PointF mLastDrag = new PointF();
@NonNull
private final WindowMagnifierCallback mWindowMagnifierCallback;
@@ -123,9 +124,12 @@
private int mNavGestureHeight;
private final SfVsyncFrameCallbackProvider mSfVsyncFrameProvider;
+ private final MagnificationGestureDetector mGestureDetector;
+ private final int mBounceEffectDuration;
private Choreographer.FrameCallback mMirrorViewGeometryVsyncCallback;
private Locale mLocale;
private NumberFormat mPercentFormat;
+ private float mBounceEffectAnimationScale;
@Nullable
private MirrorWindowControl mMirrorWindowControl;
@@ -147,14 +151,19 @@
mResources = mContext.getResources();
mScale = mResources.getInteger(R.integer.magnification_default_scale);
+ mBounceEffectDuration = mResources.getInteger(
+ com.android.internal.R.integer.config_shortAnimTime);
updateDimensions();
+ setInitialStartBounds();
+ computeBounceAnimationScale();
mMirrorWindowControl = mirrorWindowControl;
if (mMirrorWindowControl != null) {
mMirrorWindowControl.setWindowDelegate(this);
}
mTransaction = transaction;
- setInitialStartBounds();
+ mGestureDetector =
+ new MagnificationGestureDetector(mContext, handler, this);
// Initialize listeners.
mMirrorViewRunnable = () -> {
@@ -203,6 +212,13 @@
updateNavigationBarDimensions();
}
+ private void computeBounceAnimationScale() {
+ final float windowWidth = mMagnificationFrame.width() + 2 * mMirrorSurfaceMargin;
+ final float visibleWindowWidth = windowWidth - 2 * mOuterBorderSize;
+ final float animationScaleMax = windowWidth / visibleWindowWidth;
+ mBounceEffectAnimationScale = Math.min(animationScaleMax, ANIMATION_BOUNCE_EFFECT_SCALE);
+ }
+
private void updateNavigationBarDimensions() {
if (!supportsSwipeUpGesture()) {
mNavGestureHeight = 0;
@@ -248,6 +264,7 @@
void onConfigurationChanged(int configDiff) {
if ((configDiff & ActivityInfo.CONFIG_DENSITY) != 0) {
updateDimensions();
+ computeBounceAnimationScale();
if (isWindowVisible()) {
deleteWindowMagnification();
enableWindowMagnification(Float.NaN, Float.NaN, Float.NaN);
@@ -483,20 +500,7 @@
public boolean onTouch(View v, MotionEvent event) {
if (v == mDragView || v == mLeftDrag || v == mTopDrag || v == mRightDrag
|| v == mBottomDrag) {
- return handleDragTouchEvent(event);
- }
- return false;
- }
-
- private boolean handleDragTouchEvent(MotionEvent event) {
- switch (event.getAction()) {
- case MotionEvent.ACTION_DOWN:
- mLastDrag.set(event.getRawX(), event.getRawY());
- return true;
- case MotionEvent.ACTION_MOVE:
- moveWindowMagnifier(event.getRawX() - mLastDrag.x, event.getRawY() - mLastDrag.y);
- mLastDrag.set(event.getRawX(), event.getRawY());
- return true;
+ return mGestureDetector.onTouch(event);
}
return false;
}
@@ -685,6 +689,36 @@
return mPercentFormat.format(scale);
}
+ @Override
+ public boolean onSingleTap() {
+ animateBounceEffect();
+ return true;
+ }
+
+ @Override
+ public boolean onDrag(float offsetX, float offsetY) {
+ moveWindowMagnifier(offsetX, offsetY);
+ return true;
+ }
+
+ @Override
+ public boolean onStart(float x, float y) {
+ return true;
+ }
+
+ @Override
+ public boolean onFinish(float x, float y) {
+ return false;
+ }
+
+ private void animateBounceEffect() {
+ final ObjectAnimator scaleAnimator = ObjectAnimator.ofPropertyValuesHolder(mMirrorView,
+ PropertyValuesHolder.ofFloat(View.SCALE_X, 1, mBounceEffectAnimationScale, 1),
+ PropertyValuesHolder.ofFloat(View.SCALE_Y, 1, mBounceEffectAnimationScale, 1));
+ scaleAnimator.setDuration(mBounceEffectDuration);
+ scaleAnimator.start();
+ }
+
private class MirrorWindowA11yDelegate extends View.AccessibilityDelegate {
@Override
diff --git a/packages/SystemUI/src/com/android/systemui/classifier/BrightLineFalsingManager.java b/packages/SystemUI/src/com/android/systemui/classifier/BrightLineFalsingManager.java
index e78057f..6572ca9 100644
--- a/packages/SystemUI/src/com/android/systemui/classifier/BrightLineFalsingManager.java
+++ b/packages/SystemUI/src/com/android/systemui/classifier/BrightLineFalsingManager.java
@@ -18,6 +18,7 @@
import static com.android.systemui.classifier.FalsingManagerProxy.FALSING_SUCCESS;
import static com.android.systemui.classifier.FalsingModule.BRIGHT_LINE_GESTURE_CLASSIFERS;
+import static com.android.systemui.classifier.FalsingModule.DOUBLE_TAP_TIMEOUT_MS;
import android.net.Uri;
import android.os.Build;
@@ -28,23 +29,26 @@
import com.android.internal.logging.MetricsLogger;
import com.android.systemui.classifier.FalsingDataProvider.SessionListener;
+import com.android.systemui.dagger.qualifiers.Main;
import com.android.systemui.dagger.qualifiers.TestHarness;
import com.android.systemui.dock.DockManager;
import com.android.systemui.plugins.FalsingManager;
+import com.android.systemui.util.concurrency.DelayableExecutor;
import com.android.systemui.util.sensors.ThresholdSensor;
-import com.android.systemui.util.time.SystemClock;
import java.io.FileDescriptor;
import java.io.PrintWriter;
import java.util.ArrayDeque;
import java.util.ArrayList;
import java.util.Collection;
+import java.util.Collections;
import java.util.List;
import java.util.Locale;
import java.util.Queue;
import java.util.Set;
import java.util.StringJoiner;
import java.util.stream.Collectors;
+import java.util.stream.Stream;
import javax.inject.Inject;
import javax.inject.Named;
@@ -65,7 +69,8 @@
private final SingleTapClassifier mSingleTapClassifier;
private final DoubleTapClassifier mDoubleTapClassifier;
private final HistoryTracker mHistoryTracker;
- private final SystemClock mSystemClock;
+ private final DelayableExecutor mDelayableExecutor;
+ private final long mDoubleTapTimeMs;
private final boolean mTestHarness;
private final MetricsLogger mMetricsLogger;
private int mIsFalseTouchCalls;
@@ -90,23 +95,44 @@
private final FalsingDataProvider.GestureCompleteListener mGestureCompleteListener =
new FalsingDataProvider.GestureCompleteListener() {
- @Override
- public void onGestureComplete() {
- mHistoryTracker.addResults(
- mClassifiers.stream().map(FalsingClassifier::classifyGesture)
- .collect(Collectors.toCollection(ArrayList::new)),
- mSystemClock.uptimeMillis());
+ @Override
+ public void onGestureComplete(long completionTimeMs) {
+ if (mPriorResults != null) {
+ // Single taps that may become double taps don't get added right away.
+ if (mClassifyAsSingleTap) {
+ Collection<FalsingClassifier.Result> singleTapResults = mPriorResults;
+ mSingleTapHistoryCanceller = mDelayableExecutor.executeDelayed(
+ () -> {
+ mSingleTapHistoryCanceller = null;
+ mHistoryTracker.addResults(singleTapResults, completionTimeMs);
+ },
+ mDoubleTapTimeMs);
+ mClassifyAsSingleTap = false; // Don't treat things as single taps by default.
+ } else {
+ mHistoryTracker.addResults(mPriorResults, completionTimeMs);
+ }
+ mPriorResults = null;
+ } else {
+ // Gestures that were not classified get treated as a false.
+ mHistoryTracker.addResults(
+ Collections.singleton(
+ FalsingClassifier.Result.falsed(.8, "unclassified")),
+ completionTimeMs);
+ }
}
};
- private boolean mPreviousResult = false;
+ private Collection<FalsingClassifier.Result> mPriorResults;
+ private boolean mClassifyAsSingleTap;
+ private Runnable mSingleTapHistoryCanceller;
@Inject
public BrightLineFalsingManager(FalsingDataProvider falsingDataProvider,
DockManager dockManager, MetricsLogger metricsLogger,
@Named(BRIGHT_LINE_GESTURE_CLASSIFERS) Set<FalsingClassifier> classifiers,
SingleTapClassifier singleTapClassifier, DoubleTapClassifier doubleTapClassifier,
- HistoryTracker historyTracker, SystemClock systemClock,
+ HistoryTracker historyTracker, @Main DelayableExecutor delayableExecutor,
+ @Named(DOUBLE_TAP_TIMEOUT_MS) long doubleTapTimeMs,
@TestHarness boolean testHarness) {
mDataProvider = falsingDataProvider;
mDockManager = dockManager;
@@ -115,7 +141,8 @@
mSingleTapClassifier = singleTapClassifier;
mDoubleTapClassifier = doubleTapClassifier;
mHistoryTracker = historyTracker;
- mSystemClock = systemClock;
+ mDelayableExecutor = delayableExecutor;
+ mDoubleTapTimeMs = doubleTapTimeMs;
mTestHarness = testHarness;
mDataProvider.addSessionListener(mSessionListener);
@@ -129,38 +156,51 @@
@Override
public boolean isFalseTouch(@Classifier.InteractionType int interactionType) {
+ boolean result;
+
+ mClassifyAsSingleTap = false;
mDataProvider.setInteractionType(interactionType);
- if (!mDataProvider.isDirty()) {
- return mPreviousResult;
+
+ if (!mTestHarness && !mDataProvider.isJustUnlockedWithFace() && !mDockManager.isDocked()) {
+ Stream<FalsingClassifier.Result> results =
+ mClassifiers.stream().map(falsingClassifier -> {
+ FalsingClassifier.Result classifierResult =
+ falsingClassifier.classifyGesture(
+ mHistoryTracker.falsePenalty(),
+ mHistoryTracker.falseConfidence());
+ if (classifierResult.isFalse()) {
+ logInfo(String.format(
+ (Locale) null,
+ "{classifier=%s, interactionType=%d}",
+ falsingClassifier.getClass().getName(),
+ mDataProvider.getInteractionType()));
+ String reason = classifierResult.getReason();
+ if (reason != null) {
+ logInfo(reason);
+ }
+ } else {
+ logDebug(falsingClassifier.getClass().getName() + ": false");
+ }
+ return classifierResult;
+ });
+ mPriorResults = new ArrayList<>();
+ final boolean[] localResult = {false};
+ results.forEach(classifierResult -> {
+ localResult[0] |= classifierResult.isFalse();
+ mPriorResults.add(classifierResult);
+ });
+ result = localResult[0];
+ } else {
+ result = false;
+ mPriorResults = Collections.singleton(FalsingClassifier.Result.passed(1));
}
- mPreviousResult = !mTestHarness
- && !mDataProvider.isJustUnlockedWithFace() && !mDockManager.isDocked()
- && mClassifiers.stream().anyMatch(falsingClassifier -> {
- FalsingClassifier.Result result = falsingClassifier.classifyGesture(
- mHistoryTracker.falsePenalty(), mHistoryTracker.falseConfidence());
- if (result.isFalse()) {
- logInfo(String.format(
- (Locale) null,
- "{classifier=%s, interactionType=%d}",
- falsingClassifier.getClass().getName(),
- mDataProvider.getInteractionType()));
- String reason = result.getReason();
- if (reason != null) {
- logInfo(reason);
- }
- } else {
- logDebug(falsingClassifier.getClass().getName() + ": false");
- }
- return result.isFalse();
- });
-
- logDebug("Is false touch? " + mPreviousResult);
+ logDebug("Is false touch? " + result);
if (Build.IS_ENG || Build.IS_USERDEBUG) {
// Copy motion events, as the passed in list gets emptied out elsewhere in the code.
RECENT_SWIPES.add(new DebugSwipeRecord(
- mPreviousResult,
+ result,
mDataProvider.getInteractionType(),
mDataProvider.getRecentMotionEvents().stream().map(
motionEvent -> new XYDt(
@@ -173,13 +213,16 @@
}
}
- return mPreviousResult;
+ return result;
}
@Override
public boolean isFalseTap(boolean robustCheck) {
+ mClassifyAsSingleTap = true;
+
FalsingClassifier.Result singleTapResult =
mSingleTapClassifier.isTap(mDataProvider.getRecentMotionEvents());
+ mPriorResults = Collections.singleton(singleTapResult);
if (singleTapResult.isFalse()) {
logInfo(String.format(
(Locale) null, "{classifier=%s}", mSingleTapClassifier.getClass().getName()));
@@ -192,7 +235,12 @@
// TODO(b/172655679): More heuristics to come. For now, allow touches through if face-authed
if (robustCheck) {
- return !mDataProvider.isJustUnlockedWithFace();
+ boolean result = !mDataProvider.isJustUnlockedWithFace();
+ mPriorResults = Collections.singleton(
+ result ? FalsingClassifier.Result.falsed(0.1, "no face detected")
+ : FalsingClassifier.Result.passed(1));
+
+ return result;
}
return false;
@@ -200,7 +248,9 @@
@Override
public boolean isFalseDoubleTap() {
+ mClassifyAsSingleTap = false;
FalsingClassifier.Result result = mDoubleTapClassifier.classifyGesture();
+ mPriorResults = Collections.singleton(result);
if (result.isFalse()) {
logInfo(String.format(
(Locale) null, "{classifier=%s}", mDoubleTapClassifier.getClass().getName()));
@@ -208,6 +258,12 @@
if (reason != null) {
logInfo(reason);
}
+ } else {
+ // A valid double tap prevents an invalid single tap from going into history.
+ if (mSingleTapHistoryCanceller != null) {
+ mSingleTapHistoryCanceller.run();
+ mSingleTapHistoryCanceller = null;
+ }
}
return result.isFalse();
}
diff --git a/packages/SystemUI/src/com/android/systemui/classifier/FalsingCollector.java b/packages/SystemUI/src/com/android/systemui/classifier/FalsingCollector.java
index fe47162..b0bbab3 100644
--- a/packages/SystemUI/src/com/android/systemui/classifier/FalsingCollector.java
+++ b/packages/SystemUI/src/com/android/systemui/classifier/FalsingCollector.java
@@ -116,6 +116,9 @@
void onTouchEvent(MotionEvent ev);
/** */
+ void avoidGesture();
+
+ /** */
void cleanup();
}
diff --git a/packages/SystemUI/src/com/android/systemui/classifier/FalsingCollectorFake.java b/packages/SystemUI/src/com/android/systemui/classifier/FalsingCollectorFake.java
index fd05989..12a0604 100644
--- a/packages/SystemUI/src/com/android/systemui/classifier/FalsingCollectorFake.java
+++ b/packages/SystemUI/src/com/android/systemui/classifier/FalsingCollectorFake.java
@@ -147,6 +147,10 @@
}
@Override
+ public void avoidGesture() {
+ }
+
+ @Override
public void cleanup() {
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/classifier/FalsingCollectorImpl.java b/packages/SystemUI/src/com/android/systemui/classifier/FalsingCollectorImpl.java
index 4c11ecf..e08b43b 100644
--- a/packages/SystemUI/src/com/android/systemui/classifier/FalsingCollectorImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/classifier/FalsingCollectorImpl.java
@@ -49,6 +49,8 @@
private boolean mShowingAod;
private boolean mScreenOn;
private boolean mSessionStarted;
+ private MotionEvent mPendingDownEvent;
+ private boolean mAvoidGesture;
private final ThresholdSensor.Listener mSensorEventListener = this::onProximityEvent;
@@ -245,7 +247,32 @@
@Override
public void onTouchEvent(MotionEvent ev) {
- mFalsingDataProvider.onMotionEvent(ev);
+ // We delay processing down events to see if another component wants to process them.
+ // If #avoidGesture is called after a MotionEvent.ACTION_DOWN, all following motion events
+ // will be ignored by the collector until another MotionEvent.ACTION_DOWN is passed in.
+ // avoidGesture must be called immediately following the MotionEvent.ACTION_DOWN, before
+ // any other events are processed, otherwise the whole gesture will be recorded.
+ if (ev.getActionMasked() == MotionEvent.ACTION_DOWN) {
+ // Make a copy of ev, since it will be recycled after we exit this method.
+ mPendingDownEvent = MotionEvent.obtain(ev);
+ mAvoidGesture = false;
+ } else if (!mAvoidGesture) {
+ if (mPendingDownEvent != null) {
+ mFalsingDataProvider.onMotionEvent(mPendingDownEvent);
+ mPendingDownEvent.recycle();
+ mPendingDownEvent = null;
+ }
+ mFalsingDataProvider.onMotionEvent(ev);
+ }
+ }
+
+ @Override
+ public void avoidGesture() {
+ if (mPendingDownEvent != null) {
+ mAvoidGesture = true;
+ mPendingDownEvent.recycle();
+ mPendingDownEvent = null;
+ }
}
@Override
diff --git a/packages/SystemUI/src/com/android/systemui/classifier/FalsingDataProvider.java b/packages/SystemUI/src/com/android/systemui/classifier/FalsingDataProvider.java
index deb9e6d..4bacc15 100644
--- a/packages/SystemUI/src/com/android/systemui/classifier/FalsingDataProvider.java
+++ b/packages/SystemUI/src/com/android/systemui/classifier/FalsingDataProvider.java
@@ -90,10 +90,8 @@
}
if (motionEvent.getActionMasked() == MotionEvent.ACTION_DOWN) {
- if (!mRecentMotionEvents.isEmpty()) {
- mExtendedMotionEvents.addFirst(mRecentMotionEvents);
- mRecentMotionEvents = new TimeLimitedMotionEventBuffer(MOTION_EVENT_AGE_MS);
- }
+ completePriorGesture();
+ mRecentMotionEvents = new TimeLimitedMotionEventBuffer(MOTION_EVENT_AGE_MS);
}
mRecentMotionEvents.addAll(motionEvents);
@@ -101,9 +99,25 @@
mMotionEventListeners.forEach(listener -> listener.onMotionEvent(motionEvent));
+ // We explicitly do not complete a gesture on UP or CANCEL events.
+ // We wait for the next gesture to start before marking the prior gesture as complete. This
+ // has multiple benefits. First, it makes it trivial to track the "current" or "recent"
+ // gesture, as it will always be found in mRecentMotionEvents. Second, and most importantly,
+ // it ensures that the current gesture doesn't get added to this HistoryTracker before it
+ // is analyzed.
+
mDirty = true;
}
+ private void completePriorGesture() {
+ if (!mRecentMotionEvents.isEmpty()) {
+ mGestuerCompleteListeners.forEach(listener -> listener.onGestureComplete(
+ mRecentMotionEvents.get(mRecentMotionEvents.size() - 1).getEventTime()));
+
+ mExtendedMotionEvents.addFirst(mRecentMotionEvents);
+ }
+ }
+
/** Returns screen width in pixels. */
public int getWidthPixels() {
return mWidthPixels;
@@ -146,13 +160,6 @@
}
}
- /**
- * Returns true if new data has been supplied since the last time this class has been accessed.
- */
- public boolean isDirty() {
- return mDirty;
- }
-
/** Return the interaction type that is being compared against for falsing. */
public final int getInteractionType() {
return mInteractionType;
@@ -387,6 +394,6 @@
/** Callback to be alerted when the current gesture ends. */
public interface GestureCompleteListener {
/** */
- void onGestureComplete();
+ void onGestureComplete(long completionTimeMs);
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/screenshot/ImageExporter.java b/packages/SystemUI/src/com/android/systemui/screenshot/ImageExporter.java
new file mode 100644
index 0000000..2719d3e
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/screenshot/ImageExporter.java
@@ -0,0 +1,360 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.screenshot;
+
+import static android.os.FileUtils.closeQuietly;
+
+import android.annotation.IntRange;
+import android.content.ContentResolver;
+import android.content.ContentValues;
+import android.graphics.Bitmap;
+import android.graphics.Bitmap.CompressFormat;
+import android.net.Uri;
+import android.os.Build;
+import android.os.Environment;
+import android.os.ParcelFileDescriptor;
+import android.os.SystemClock;
+import android.os.Trace;
+import android.provider.MediaStore;
+import android.util.Log;
+
+import androidx.concurrent.futures.CallbackToFutureAdapter;
+import androidx.exifinterface.media.ExifInterface;
+
+import com.google.common.util.concurrent.ListenableFuture;
+
+import java.io.File;
+import java.io.FileNotFoundException;
+import java.io.IOException;
+import java.io.OutputStream;
+import java.time.Duration;
+import java.time.Instant;
+import java.time.ZonedDateTime;
+import java.time.format.DateTimeFormatter;
+import java.util.concurrent.Executor;
+
+import javax.inject.Inject;
+
+class ImageExporter {
+ private static final String TAG = LogConfig.logTag(ImageExporter.class);
+
+ static final Duration PENDING_ENTRY_TTL = Duration.ofHours(24);
+
+ // ex: 'Screenshot_20201215-090626.png'
+ private static final String FILENAME_PATTERN = "Screenshot_%1$tY%<tm%<td-%<tH%<tM%<tS.%2$s";
+ private static final String SCREENSHOTS_PATH = Environment.DIRECTORY_PICTURES
+ + File.separator + Environment.DIRECTORY_SCREENSHOTS;
+
+ private static final String RESOLVER_INSERT_RETURNED_NULL =
+ "ContentResolver#insert returned null.";
+ private static final String RESOLVER_OPEN_FILE_RETURNED_NULL =
+ "ContentResolver#openFile returned null.";
+ private static final String RESOLVER_OPEN_FILE_EXCEPTION =
+ "ContentResolver#openFile threw an exception.";
+ private static final String OPEN_OUTPUT_STREAM_EXCEPTION =
+ "ContentResolver#openOutputStream threw an exception.";
+ private static final String EXIF_READ_EXCEPTION =
+ "ExifInterface threw an exception reading from the file descriptor.";
+ private static final String EXIF_WRITE_EXCEPTION =
+ "ExifInterface threw an exception writing to the file descriptor.";
+ private static final String RESOLVER_UPDATE_ZERO_ROWS =
+ "Failed to publishEntry. ContentResolver#update reported no rows updated.";
+ private static final String IMAGE_COMPRESS_RETURNED_FALSE =
+ "Bitmap.compress returned false. (Failure unknown)";
+
+ private final ContentResolver mResolver;
+ private CompressFormat mCompressFormat = CompressFormat.PNG;
+ private int mQuality = 100;
+
+ @Inject
+ ImageExporter(ContentResolver resolver) {
+ mResolver = resolver;
+ }
+
+ /**
+ * Adjusts the output image format. This also determines extension of the filename created. The
+ * default is {@link CompressFormat#PNG PNG}.
+ *
+ * @see CompressFormat
+ *
+ * @param format the image format for export
+ */
+ void setFormat(CompressFormat format) {
+ mCompressFormat = format;
+ }
+
+ /**
+ * Sets the quality format. The exact meaning is dependent on the {@link CompressFormat} used.
+ *
+ * @param quality the 'quality' level between 0 and 100
+ */
+ void setQuality(@IntRange(from = 0, to = 100) int quality) {
+ mQuality = quality;
+ }
+
+ /**
+ * Export the image using the given executor.
+ *
+ * @param executor the thread for execution
+ * @param bitmap the bitmap to export
+ *
+ * @return a listenable future result
+ */
+ ListenableFuture<Uri> export(Executor executor, Bitmap bitmap) {
+ return export(executor, bitmap, ZonedDateTime.now());
+ }
+
+ /**
+ * Export the image using the given executor.
+ *
+ * @param executor the thread for execution
+ * @param bitmap the bitmap to export
+ *
+ * @return a listenable future result
+ */
+ ListenableFuture<Uri> export(Executor executor, Bitmap bitmap, ZonedDateTime captureTime) {
+ final Task task = new Task(mResolver, bitmap, captureTime, mCompressFormat, mQuality);
+ return CallbackToFutureAdapter.getFuture(
+ (completer) -> {
+ executor.execute(() -> {
+ try {
+ completer.set(task.execute());
+ } catch (ImageExportException | InterruptedException e) {
+ completer.setException(e);
+ }
+ });
+ return task;
+ }
+ );
+ }
+
+ private static class Task {
+ private final ContentResolver mResolver;
+ private final ZonedDateTime mCaptureTime;
+ private final CompressFormat mFormat;
+ private final int mQuality;
+ private final Bitmap mBitmap;
+
+ Task(ContentResolver resolver, Bitmap bitmap, ZonedDateTime captureTime,
+ CompressFormat format, int quality) {
+ mResolver = resolver;
+ mBitmap = bitmap;
+ mCaptureTime = captureTime;
+ mFormat = format;
+ mQuality = quality;
+ }
+
+ public Uri execute() throws ImageExportException, InterruptedException {
+ Trace.beginSection("ImageExporter_execute");
+ Uri uri = null;
+ Instant start = null;
+ try {
+ if (LogConfig.DEBUG_STORAGE) {
+ Log.d(TAG, "image export started");
+ start = Instant.now();
+ }
+ uri = createEntry(mFormat, mCaptureTime);
+ throwIfInterrupted();
+
+ writeImage(mBitmap, mFormat, mQuality, uri);
+ throwIfInterrupted();
+
+ writeExif(uri, mBitmap.getWidth(), mBitmap.getHeight(), mCaptureTime);
+ throwIfInterrupted();
+
+ publishEntry(uri);
+
+ if (LogConfig.DEBUG_STORAGE) {
+ Log.d(TAG, "image export completed: "
+ + Duration.between(start, Instant.now()).toMillis() + " ms");
+ }
+ } catch (ImageExportException e) {
+ if (uri != null) {
+ mResolver.delete(uri, null);
+ }
+ throw e;
+ } finally {
+ Trace.endSection();
+ }
+ return uri;
+ }
+
+ Uri createEntry(CompressFormat format, ZonedDateTime time) throws ImageExportException {
+ Trace.beginSection("ImageExporter_createEntry");
+ try {
+ final ContentValues values = createMetadata(time, format);
+ Uri uri = mResolver.insert(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, values);
+ if (uri == null) {
+ throw new ImageExportException(RESOLVER_INSERT_RETURNED_NULL);
+ }
+ return uri;
+ } finally {
+ Trace.endSection();
+ }
+ }
+
+ void writeImage(Bitmap bitmap, CompressFormat format, int quality,
+ Uri contentUri) throws ImageExportException {
+ Trace.beginSection("ImageExporter_writeImage");
+ try (OutputStream out = mResolver.openOutputStream(contentUri)) {
+ long start = SystemClock.elapsedRealtime();
+ if (!bitmap.compress(format, quality, out)) {
+ throw new ImageExportException(IMAGE_COMPRESS_RETURNED_FALSE);
+ } else if (LogConfig.DEBUG_STORAGE) {
+ Log.d(TAG, "Bitmap.compress took "
+ + (SystemClock.elapsedRealtime() - start) + " ms");
+ }
+ } catch (IOException ex) {
+ throw new ImageExportException(OPEN_OUTPUT_STREAM_EXCEPTION, ex);
+ } finally {
+ Trace.endSection();
+ }
+ }
+
+ void writeExif(Uri uri, int width, int height, ZonedDateTime captureTime)
+ throws ImageExportException {
+ Trace.beginSection("ImageExporter_writeExif");
+ ParcelFileDescriptor pfd = null;
+ try {
+ pfd = mResolver.openFile(uri, "rw", null);
+ if (pfd == null) {
+ throw new ImageExportException(RESOLVER_OPEN_FILE_RETURNED_NULL);
+ }
+ ExifInterface exif;
+ try {
+ exif = new ExifInterface(pfd.getFileDescriptor());
+ } catch (IOException e) {
+ throw new ImageExportException(EXIF_READ_EXCEPTION, e);
+ }
+
+ updateExifAttributes(exif, width, height, captureTime);
+ try {
+ exif.saveAttributes();
+ } catch (IOException e) {
+ throw new ImageExportException(EXIF_WRITE_EXCEPTION, e);
+ }
+ } catch (FileNotFoundException e) {
+ throw new ImageExportException(RESOLVER_OPEN_FILE_EXCEPTION, e);
+ } finally {
+ closeQuietly(pfd);
+ Trace.endSection();
+ }
+ }
+
+ void publishEntry(Uri uri) throws ImageExportException {
+ Trace.beginSection("ImageExporter_publishEntry");
+ try {
+ ContentValues values = new ContentValues();
+ values.put(MediaStore.MediaColumns.IS_PENDING, 0);
+ values.putNull(MediaStore.MediaColumns.DATE_EXPIRES);
+ final int rowsUpdated = mResolver.update(uri, values, /* extras */ null);
+ if (rowsUpdated < 1) {
+ throw new ImageExportException(RESOLVER_UPDATE_ZERO_ROWS);
+ }
+ } finally {
+ Trace.endSection();
+ }
+ }
+
+ @Override
+ public String toString() {
+ return "compress [" + mBitmap + "] to [" + mFormat + "] at quality " + mQuality;
+ }
+ }
+
+ static String createFilename(ZonedDateTime time, CompressFormat format) {
+ return String.format(FILENAME_PATTERN, time, fileExtension(format));
+ }
+
+ static ContentValues createMetadata(ZonedDateTime captureTime, CompressFormat format) {
+ ContentValues values = new ContentValues();
+ values.put(MediaStore.MediaColumns.RELATIVE_PATH, SCREENSHOTS_PATH);
+ values.put(MediaStore.MediaColumns.DISPLAY_NAME, createFilename(captureTime, format));
+ values.put(MediaStore.MediaColumns.MIME_TYPE, getMimeType(format));
+ values.put(MediaStore.MediaColumns.DATE_ADDED, captureTime.toEpochSecond());
+ values.put(MediaStore.MediaColumns.DATE_MODIFIED, captureTime.toEpochSecond());
+ values.put(MediaStore.MediaColumns.DATE_EXPIRES,
+ captureTime.plus(PENDING_ENTRY_TTL).toEpochSecond());
+ values.put(MediaStore.MediaColumns.IS_PENDING, 1);
+ return values;
+ }
+
+ static void updateExifAttributes(ExifInterface exif, int width, int height,
+ ZonedDateTime captureTime) {
+ exif.setAttribute(ExifInterface.TAG_SOFTWARE, "Android " + Build.DISPLAY);
+ exif.setAttribute(ExifInterface.TAG_IMAGE_WIDTH, Integer.toString(width));
+ exif.setAttribute(ExifInterface.TAG_IMAGE_LENGTH, Integer.toString(height));
+
+ String dateTime = DateTimeFormatter.ofPattern("yyyy:MM:dd HH:mm:ss").format(captureTime);
+ String subSec = DateTimeFormatter.ofPattern("SSS").format(captureTime);
+ String timeZone = DateTimeFormatter.ofPattern("xxx").format(captureTime);
+
+ exif.setAttribute(ExifInterface.TAG_DATETIME_ORIGINAL, dateTime);
+ exif.setAttribute(ExifInterface.TAG_SUBSEC_TIME_ORIGINAL, subSec);
+ exif.setAttribute(ExifInterface.TAG_OFFSET_TIME_ORIGINAL, timeZone);
+
+ exif.setAttribute(ExifInterface.TAG_DATETIME_DIGITIZED, dateTime);
+ exif.setAttribute(ExifInterface.TAG_SUBSEC_TIME_DIGITIZED, subSec);
+ exif.setAttribute(ExifInterface.TAG_OFFSET_TIME_DIGITIZED, timeZone);
+ }
+
+ static String getMimeType(CompressFormat format) {
+ switch (format) {
+ case JPEG:
+ return "image/jpeg";
+ case PNG:
+ return "image/png";
+ case WEBP:
+ case WEBP_LOSSLESS:
+ case WEBP_LOSSY:
+ return "image/webp";
+ default:
+ throw new IllegalArgumentException("Unknown CompressFormat!");
+ }
+ }
+
+ static String fileExtension(CompressFormat format) {
+ switch (format) {
+ case JPEG:
+ return "jpg";
+ case PNG:
+ return "png";
+ case WEBP:
+ case WEBP_LOSSY:
+ case WEBP_LOSSLESS:
+ return "webp";
+ default:
+ throw new IllegalArgumentException("Unknown CompressFormat!");
+ }
+ }
+
+ private static void throwIfInterrupted() throws InterruptedException {
+ if (Thread.currentThread().isInterrupted()) {
+ throw new InterruptedException();
+ }
+ }
+
+ static final class ImageExportException extends IOException {
+ ImageExportException(String message) {
+ super(message);
+ }
+
+ ImageExportException(String message, Throwable cause) {
+ super(message, cause);
+ }
+ }
+}
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 a991d3615..f9c7799 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java
@@ -34,7 +34,6 @@
import static com.android.systemui.keyguard.WakefulnessLifecycle.WAKEFULNESS_ASLEEP;
import static com.android.systemui.keyguard.WakefulnessLifecycle.WAKEFULNESS_AWAKE;
import static com.android.systemui.keyguard.WakefulnessLifecycle.WAKEFULNESS_WAKING;
-import static com.android.systemui.shared.system.WindowManagerWrapper.NAV_BAR_POS_INVALID;
import static com.android.systemui.statusbar.LightRevealScrimKt.getEnableLightReveal;
import static com.android.systemui.statusbar.NotificationLockscreenUserManager.PERMISSION_SELF;
import static com.android.systemui.statusbar.phone.BarTransitions.MODE_LIGHTS_OUT;
@@ -176,7 +175,6 @@
import com.android.systemui.recents.ScreenPinningRequest;
import com.android.systemui.settings.brightness.BrightnessSlider;
import com.android.systemui.shared.plugins.PluginManager;
-import com.android.systemui.shared.system.WindowManagerWrapper;
import com.android.systemui.statusbar.AutoHideUiElement;
import com.android.systemui.statusbar.BackDropView;
import com.android.systemui.statusbar.CommandQueue;
@@ -1582,11 +1580,6 @@
return true;
}
- final int navbarPos = WindowManagerWrapper.getInstance().getNavBarPosition(mDisplayId);
- if (navbarPos == NAV_BAR_POS_INVALID) {
- return false;
- }
-
if (legacySplitScreen.splitPrimaryTask()) {
if (metricsDockAction != -1) {
mMetricsLogger.action(metricsDockAction);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/BatteryController.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/BatteryController.java
index 08e70a9..6ae5e90 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/BatteryController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/BatteryController.java
@@ -105,6 +105,9 @@
default void onExtremeBatterySaverChanged(boolean isExtreme) {
}
+
+ default void onWirelessChargingChanged(boolean isWirlessCharging) {
+ }
}
/**
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/BatteryControllerImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/BatteryControllerImpl.java
index 8c67072..da9aa97 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/BatteryControllerImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/BatteryControllerImpl.java
@@ -77,7 +77,7 @@
private boolean mCharged;
protected boolean mPowerSave;
private boolean mAodPowerSave;
- protected boolean mWirelessCharging;
+ private boolean mWirelessCharging;
private boolean mTestMode = false;
@VisibleForTesting
boolean mHasReceivedBattery = false;
@@ -155,6 +155,7 @@
cb.onBatteryLevelChanged(mLevel, mPluggedIn, mCharging);
cb.onPowerSaveChanged(mPowerSave);
cb.onBatteryUnknownStateChanged(mStateUnknown);
+ cb.onWirelessChargingChanged(mWirelessCharging);
}
@Override
@@ -179,8 +180,12 @@
BatteryManager.BATTERY_STATUS_UNKNOWN);
mCharged = status == BatteryManager.BATTERY_STATUS_FULL;
mCharging = mCharged || status == BatteryManager.BATTERY_STATUS_CHARGING;
- mWirelessCharging = mCharging && intent.getIntExtra(BatteryManager.EXTRA_PLUGGED, 0)
- == BatteryManager.BATTERY_PLUGGED_WIRELESS;
+ if (mWirelessCharging != (mCharging
+ && intent.getIntExtra(BatteryManager.EXTRA_PLUGGED, 0)
+ == BatteryManager.BATTERY_PLUGGED_WIRELESS)) {
+ mWirelessCharging = !mWirelessCharging;
+ fireWirelessChargingChanged();
+ }
boolean present = intent.getBooleanExtra(EXTRA_PRESENT, true);
boolean unknown = !present;
@@ -227,6 +232,13 @@
}
}
+ private void fireWirelessChargingChanged() {
+ synchronized (mChangeCallbacks) {
+ mChangeCallbacks.forEach(batteryStateChangeCallback ->
+ batteryStateChangeCallback.onWirelessChargingChanged(mWirelessCharging));
+ }
+ }
+
@Override
public boolean isPluggedIn() {
return mPluggedIn;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/tv/notifications/TvNotificationPanel.java b/packages/SystemUI/src/com/android/systemui/statusbar/tv/notifications/TvNotificationPanel.java
index 477424c..c9bc7e6 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/tv/notifications/TvNotificationPanel.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/tv/notifications/TvNotificationPanel.java
@@ -91,6 +91,7 @@
private void openInternalNotificationPanel(String action) {
Intent intent = new Intent(mContext, TvNotificationPanelActivity.class);
+ intent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP | Intent.FLAG_ACTIVITY_SINGLE_TOP);
intent.setAction(action);
mContext.startActivityAsUser(intent, UserHandle.SYSTEM);
}
@@ -113,6 +114,7 @@
if (ri != null && ri.activityInfo != null) {
if (ri.activityInfo.permission != null && ri.activityInfo.permission.equals(
Manifest.permission.STATUS_BAR_SERVICE)) {
+ intent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP | Intent.FLAG_ACTIVITY_SINGLE_TOP);
mContext.startActivityAsUser(intent, UserHandle.CURRENT);
} else {
Log.e(TAG,
diff --git a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardPinBasedInputViewControllerTest.java b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardPinBasedInputViewControllerTest.java
index 4944284..31cc7bb 100644
--- a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardPinBasedInputViewControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardPinBasedInputViewControllerTest.java
@@ -31,6 +31,8 @@
import com.android.keyguard.KeyguardSecurityModel.SecurityMode;
import com.android.systemui.R;
import com.android.systemui.SysuiTestCase;
+import com.android.systemui.classifier.FalsingCollector;
+import com.android.systemui.classifier.FalsingCollectorFake;
import org.junit.Before;
import org.junit.Test;
@@ -65,6 +67,7 @@
private LatencyTracker mLatencyTracker;
@Mock
private LiftToActivateListener mLiftToactivateListener;
+ private FalsingCollector mFalsingCollector = new FalsingCollectorFake();
@Mock
private View mDeleteButton;
@Mock
@@ -88,7 +91,8 @@
.thenReturn(mOkButton);
mKeyguardPinViewController = new KeyguardPinBasedInputViewController(mPinBasedInputView,
mKeyguardUpdateMonitor, mSecurityMode, mLockPatternUtils, mKeyguardSecurityCallback,
- mKeyguardMessageAreaControllerFactory, mLatencyTracker, mLiftToactivateListener) {
+ mKeyguardMessageAreaControllerFactory, mLatencyTracker, mLiftToactivateListener,
+ mFalsingCollector) {
@Override
public void onResume(int reason) {
super.onResume(reason);
diff --git a/packages/SystemUI/tests/src/com/android/systemui/accessibility/MagnificationGestureDetectorTest.java b/packages/SystemUI/tests/src/com/android/systemui/accessibility/MagnificationGestureDetectorTest.java
new file mode 100644
index 0000000..6f4846a
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/accessibility/MagnificationGestureDetectorTest.java
@@ -0,0 +1,173 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.accessibility;
+
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.anyFloat;
+import static org.mockito.ArgumentMatchers.anyLong;
+import static org.mockito.Mockito.doAnswer;
+import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.verify;
+
+import android.os.Handler;
+import android.os.SystemClock;
+import android.testing.AndroidTestingRunner;
+import android.view.MotionEvent;
+import android.view.ViewConfiguration;
+
+import androidx.test.filters.SmallTest;
+
+import com.android.systemui.SysuiTestCase;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.InOrder;
+import org.mockito.Mock;
+import org.mockito.Mockito;
+import org.mockito.MockitoAnnotations;
+
+
+@SmallTest
+@RunWith(AndroidTestingRunner.class)
+public class MagnificationGestureDetectorTest extends SysuiTestCase {
+
+ private static final float ACTION_DOWN_X = 100;
+ private static final float ACTION_DOWN_Y = 200;
+ private int mTouchSlop = ViewConfiguration.get(getContext()).getScaledTouchSlop();
+ private MagnificationGestureDetector mGestureDetector;
+ private MotionEventHelper mMotionEventHelper = new MotionEventHelper();
+ @Mock
+ private MagnificationGestureDetector.OnGestureListener mListener;
+ @Mock
+ private Handler mHandler;
+ private Runnable mCancelSingleTapRunnable;
+
+ @Before
+ public void setUp() throws Exception {
+ MockitoAnnotations.initMocks(this);
+ doAnswer((invocation) -> {
+ mCancelSingleTapRunnable = invocation.getArgument(0);
+ return null;
+ }).when(mHandler).postAtTime(any(Runnable.class), anyLong());
+ mGestureDetector = new MagnificationGestureDetector(mContext, mHandler, mListener);
+ }
+
+ @After
+ public void tearDown() {
+ mMotionEventHelper.recycleEvents();
+ }
+
+ @Test
+ public void onActionDown_invokeDownCallback() {
+ final long downTime = SystemClock.uptimeMillis();
+ final MotionEvent downEvent = mMotionEventHelper.obtainMotionEvent(downTime, downTime,
+ MotionEvent.ACTION_DOWN, ACTION_DOWN_X, ACTION_DOWN_Y);
+
+ mGestureDetector.onTouch(downEvent);
+
+ mListener.onStart(ACTION_DOWN_X, ACTION_DOWN_Y);
+ }
+
+ @Test
+ public void performSingleTap_invokeCallbacksInOrder() {
+ final long downTime = SystemClock.uptimeMillis();
+ final MotionEvent downEvent = mMotionEventHelper.obtainMotionEvent(downTime, downTime,
+ MotionEvent.ACTION_DOWN, ACTION_DOWN_X, ACTION_DOWN_Y);
+ final MotionEvent upEvent = mMotionEventHelper.obtainMotionEvent(downTime, downTime,
+ MotionEvent.ACTION_UP, ACTION_DOWN_X, ACTION_DOWN_Y);
+
+ mGestureDetector.onTouch(downEvent);
+ mGestureDetector.onTouch(upEvent);
+
+ InOrder inOrder = Mockito.inOrder(mListener);
+ inOrder.verify(mListener).onStart(ACTION_DOWN_X, ACTION_DOWN_Y);
+ inOrder.verify(mListener).onSingleTap();
+ inOrder.verify(mListener).onFinish(ACTION_DOWN_X, ACTION_DOWN_Y);
+ verify(mListener, never()).onDrag(anyFloat(), anyFloat());
+ }
+
+ @Test
+ public void performSingleTapWithActionCancel_notInvokeOnSingleTapCallback() {
+ final long downTime = SystemClock.uptimeMillis();
+ final MotionEvent downEvent = mMotionEventHelper.obtainMotionEvent(downTime, downTime,
+ MotionEvent.ACTION_DOWN, ACTION_DOWN_X, ACTION_DOWN_Y);
+ final MotionEvent cancelEvent = mMotionEventHelper.obtainMotionEvent(downTime, downTime,
+ MotionEvent.ACTION_CANCEL, ACTION_DOWN_X, ACTION_DOWN_Y);
+
+ mGestureDetector.onTouch(downEvent);
+ mGestureDetector.onTouch(cancelEvent);
+
+ verify(mListener, never()).onSingleTap();
+ }
+
+ @Test
+ public void performSingleTapWithTwoPointers_notInvokeSingleTapCallback() {
+ final long downTime = SystemClock.uptimeMillis();
+ final MotionEvent downEvent = mMotionEventHelper.obtainMotionEvent(downTime, downTime,
+ MotionEvent.ACTION_DOWN, ACTION_DOWN_X, ACTION_DOWN_Y);
+ final MotionEvent upEvent = mMotionEventHelper.obtainMotionEvent(downTime, downTime,
+ MotionEvent.ACTION_POINTER_DOWN, ACTION_DOWN_X, ACTION_DOWN_Y);
+
+ mGestureDetector.onTouch(downEvent);
+ mGestureDetector.onTouch(upEvent);
+
+ verify(mListener, never()).onSingleTap();
+ }
+
+ @Test
+ public void performLongPress_invokeCallbacksInOrder() {
+ final long downTime = SystemClock.uptimeMillis();
+ final MotionEvent downEvent = mMotionEventHelper.obtainMotionEvent(downTime, downTime,
+ MotionEvent.ACTION_DOWN, ACTION_DOWN_X, ACTION_DOWN_Y);
+ final MotionEvent upEvent = mMotionEventHelper.obtainMotionEvent(downTime, downTime,
+ MotionEvent.ACTION_UP, ACTION_DOWN_X, ACTION_DOWN_Y);
+
+ mGestureDetector.onTouch(downEvent);
+ // Execute the pending message for stopping single-tap detection.
+ mCancelSingleTapRunnable.run();
+ mGestureDetector.onTouch(upEvent);
+
+ InOrder inOrder = Mockito.inOrder(mListener);
+ inOrder.verify(mListener).onStart(ACTION_DOWN_X, ACTION_DOWN_Y);
+ inOrder.verify(mListener).onFinish(ACTION_DOWN_X, ACTION_DOWN_Y);
+ verify(mListener, never()).onSingleTap();
+ }
+
+ @Test
+ public void performDrag_invokeCallbacksInOrder() {
+ final long downTime = SystemClock.uptimeMillis();
+ final float dragOffset = mTouchSlop + 10;
+ final MotionEvent downEvent = mMotionEventHelper.obtainMotionEvent(downTime, downTime,
+ MotionEvent.ACTION_DOWN, ACTION_DOWN_X, ACTION_DOWN_Y);
+ final MotionEvent moveEvent = mMotionEventHelper.obtainMotionEvent(downTime, downTime,
+ MotionEvent.ACTION_MOVE, ACTION_DOWN_X + dragOffset, ACTION_DOWN_Y);
+ final MotionEvent upEvent = mMotionEventHelper.obtainMotionEvent(downTime, downTime,
+ MotionEvent.ACTION_UP, ACTION_DOWN_X, ACTION_DOWN_Y);
+
+ mGestureDetector.onTouch(downEvent);
+ mGestureDetector.onTouch(moveEvent);
+ mGestureDetector.onTouch(upEvent);
+
+ InOrder inOrder = Mockito.inOrder(mListener);
+ inOrder.verify(mListener).onStart(ACTION_DOWN_X, ACTION_DOWN_Y);
+ inOrder.verify(mListener).onDrag(dragOffset, 0);
+ inOrder.verify(mListener).onFinish(ACTION_DOWN_X, ACTION_DOWN_Y);
+ verify(mListener, never()).onSingleTap();
+ }
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/accessibility/MagnificationModeSwitchTest.java b/packages/SystemUI/tests/src/com/android/systemui/accessibility/MagnificationModeSwitchTest.java
index 96f3c15..3d504fb 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/accessibility/MagnificationModeSwitchTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/accessibility/MagnificationModeSwitchTest.java
@@ -73,7 +73,6 @@
import org.mockito.Mockito;
import org.mockito.MockitoAnnotations;
-import java.util.ArrayList;
import java.util.List;
@SmallTest
@@ -91,8 +90,8 @@
private ViewPropertyAnimator mViewPropertyAnimator;
private MagnificationModeSwitch mMagnificationModeSwitch;
private View.OnTouchListener mTouchListener;
- private List<MotionEvent> mMotionEvents = new ArrayList<>();
private Runnable mFadeOutAnimation;
+ private MotionEventHelper mMotionEventHelper = new MotionEventHelper();
@Before
public void setUp() throws Exception {
@@ -117,11 +116,8 @@
@After
public void tearDown() {
- for (MotionEvent event:mMotionEvents) {
- event.recycle();
- }
- mMotionEvents.clear();
mFadeOutAnimation = null;
+ mMotionEventHelper.recycleEvents();
}
@Test
@@ -436,9 +432,7 @@
private MotionEvent obtainMotionEvent(long downTime, long eventTime, int action, float x,
float y) {
- MotionEvent event = MotionEvent.obtain(downTime, eventTime, action, x, y, 0);
- mMotionEvents.add(event);
- return event;
+ return mMotionEventHelper.obtainMotionEvent(downTime, eventTime, action, x, y);
}
private void executeFadeOutAnimation() {
diff --git a/packages/SystemUI/tests/src/com/android/systemui/accessibility/MotionEventHelper.java b/packages/SystemUI/tests/src/com/android/systemui/accessibility/MotionEventHelper.java
new file mode 100644
index 0000000..92dad9b
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/accessibility/MotionEventHelper.java
@@ -0,0 +1,47 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.accessibility;
+
+import android.view.MotionEvent;
+
+import com.android.internal.annotations.GuardedBy;
+
+import java.util.ArrayList;
+import java.util.List;
+
+class MotionEventHelper {
+ @GuardedBy("this")
+ private final List<MotionEvent> mMotionEvents = new ArrayList<>();
+
+ void recycleEvents() {
+ for (MotionEvent event:mMotionEvents) {
+ event.recycle();
+ }
+ synchronized (this) {
+ mMotionEvents.clear();
+ }
+ }
+
+ MotionEvent obtainMotionEvent(long downTime, long eventTime, int action, float x,
+ float y) {
+ MotionEvent event = MotionEvent.obtain(downTime, eventTime, action, x, y, 0);
+ synchronized (this) {
+ mMotionEvents.add(event);
+ }
+ return event;
+ }
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/accessibility/WindowMagnificationControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/accessibility/WindowMagnificationControllerTest.java
index f28322f..9659610e 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/accessibility/WindowMagnificationControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/accessibility/WindowMagnificationControllerTest.java
@@ -26,6 +26,7 @@
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertThat;
import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyInt;
import static org.mockito.ArgumentMatchers.anyLong;
@@ -40,6 +41,7 @@
import android.content.pm.ActivityInfo;
import android.content.res.Resources;
import android.os.Handler;
+import android.os.SystemClock;
import android.testing.AndroidTestingRunner;
import android.testing.TestableResources;
import android.view.Display;
@@ -347,4 +349,26 @@
verify(mWindowManager).updateViewLayout(eq(mMirrorView), paramsArgumentCaptor.capture());
assertEquals(newA11yWindowTitle, paramsArgumentCaptor.getValue().accessibilityTitle);
}
+
+ @Test
+ public void onSingleTap_enabled_scaleIsChanged() {
+ mInstrumentation.runOnMainSync(() -> {
+ mWindowMagnificationController.enableWindowMagnification(Float.NaN, Float.NaN,
+ Float.NaN);
+ });
+
+ mInstrumentation.runOnMainSync(() -> {
+ mWindowMagnificationController.onSingleTap();
+ });
+
+ final long timeout = SystemClock.uptimeMillis() + 1000;
+ while (SystemClock.uptimeMillis() < timeout) {
+ SystemClock.sleep(10);
+
+ if (Float.compare(1.0f, mMirrorView.getScaleX()) < 0) {
+ return;
+ }
+ }
+ fail("mMirrorView scale is not changed");
+ }
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/classifier/BrightLineClassifierTest.java b/packages/SystemUI/tests/src/com/android/systemui/classifier/BrightLineClassifierTest.java
index 8c547b1..5709ce30 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/classifier/BrightLineClassifierTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/classifier/BrightLineClassifierTest.java
@@ -16,12 +16,15 @@
package com.android.systemui.classifier;
-import static com.android.systemui.util.mockito.KotlinMockitoHelpersKt.any;
-
import static com.google.common.truth.Truth.assertThat;
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.anyCollection;
import static org.mockito.ArgumentMatchers.anyDouble;
+import static org.mockito.ArgumentMatchers.anyLong;
import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.reset;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
@@ -35,6 +38,7 @@
import com.android.systemui.SysuiTestCase;
import com.android.systemui.classifier.FalsingDataProvider.GestureCompleteListener;
import com.android.systemui.dock.DockManagerFake;
+import com.android.systemui.util.concurrency.FakeExecutor;
import com.android.systemui.util.time.FakeSystemClock;
import org.junit.Before;
@@ -45,7 +49,6 @@
import org.mockito.MockitoAnnotations;
import java.util.ArrayList;
-import java.util.Collection;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
@@ -53,6 +56,8 @@
@SmallTest
@RunWith(AndroidTestingRunner.class)
public class BrightLineClassifierTest extends SysuiTestCase {
+ private static final long DOUBLE_TAP_TIMEOUT_MS = 1000;
+
private BrightLineFalsingManager mBrightLineFalsingManager;
@Mock
private FalsingDataProvider mFalsingDataProvider;
@@ -69,24 +74,35 @@
private FalsingClassifier mClassifierB;
private final List<MotionEvent> mMotionEventList = new ArrayList<>();
@Mock
- private HistoryTracker mHistoryTracker;
- private FakeSystemClock mSystemClock = new FakeSystemClock();
+ private HistoryTracker mHistoryTracker;;
+ private final FakeExecutor mFakeExecutor = new FakeExecutor(new FakeSystemClock());
private final FalsingClassifier.Result mFalsedResult = FalsingClassifier.Result.falsed(1, "");
private final FalsingClassifier.Result mPassedResult = FalsingClassifier.Result.passed(1);
+ private GestureCompleteListener mGestureCompleteListener;
@Before
public void setup() {
MockitoAnnotations.initMocks(this);
when(mClassifierA.classifyGesture(anyDouble(), anyDouble())).thenReturn(mPassedResult);
when(mClassifierB.classifyGesture(anyDouble(), anyDouble())).thenReturn(mPassedResult);
+ when(mSingleTapClassfier.isTap(any(List.class))).thenReturn(mPassedResult);
+ when(mDoubleTapClassifier.classifyGesture()).thenReturn(mPassedResult);
mClassifiers.add(mClassifierA);
mClassifiers.add(mClassifierB);
- when(mFalsingDataProvider.isDirty()).thenReturn(true);
when(mFalsingDataProvider.getRecentMotionEvents()).thenReturn(mMotionEventList);
mBrightLineFalsingManager = new BrightLineFalsingManager(mFalsingDataProvider, mDockManager,
mMetricsLogger, mClassifiers, mSingleTapClassfier, mDoubleTapClassifier,
- mHistoryTracker, mSystemClock, false);
+ mHistoryTracker, mFakeExecutor, DOUBLE_TAP_TIMEOUT_MS, false);
+
+
+ ArgumentCaptor<GestureCompleteListener> gestureCompleteListenerCaptor =
+ ArgumentCaptor.forClass(GestureCompleteListener.class);
+
+ verify(mFalsingDataProvider).addGestureCompleteListener(
+ gestureCompleteListenerCaptor.capture());
+
+ mGestureCompleteListener = gestureCompleteListenerCaptor.getValue();
}
@Test
@@ -179,15 +195,57 @@
@Test
public void testHistory() {
- ArgumentCaptor<GestureCompleteListener> gestureCompleteListenerCaptor =
- ArgumentCaptor.forClass(GestureCompleteListener.class);
+ mGestureCompleteListener.onGestureComplete(1000);
- verify(mFalsingDataProvider).addGestureCompleteListener(
- gestureCompleteListenerCaptor.capture());
+ verify(mHistoryTracker).addResults(anyCollection(), eq(1000L));
+ }
- GestureCompleteListener gestureCompleteListener = gestureCompleteListenerCaptor.getValue();
- gestureCompleteListener.onGestureComplete();
+ @Test
+ public void testHistory_singleTap() {
+ // When trying to classify single taps, we don't immediately add results to history.
+ mBrightLineFalsingManager.isFalseTap(false);
+ mGestureCompleteListener.onGestureComplete(1000);
- verify(mHistoryTracker).addResults(any(Collection.class), eq(mSystemClock.uptimeMillis()));
+ verify(mHistoryTracker, never()).addResults(any(), anyLong());
+
+ mFakeExecutor.advanceClockToNext();
+ mFakeExecutor.runAllReady();
+
+ verify(mHistoryTracker).addResults(anyCollection(), eq(1000L));
+ }
+
+ @Test
+ public void testHistory_multipleSingleTaps() {
+ // When trying to classify single taps, we don't immediately add results to history.
+ mBrightLineFalsingManager.isFalseTap(false);
+ mGestureCompleteListener.onGestureComplete(1000);
+ mBrightLineFalsingManager.isFalseTap(false);
+ mGestureCompleteListener.onGestureComplete(2000);
+
+ verify(mHistoryTracker, never()).addResults(any(), anyLong());
+
+ mFakeExecutor.advanceClockToNext();
+ mFakeExecutor.runNextReady();
+ verify(mHistoryTracker).addResults(anyCollection(), eq(1000L));
+ reset(mHistoryTracker);
+ mFakeExecutor.advanceClockToNext();
+ mFakeExecutor.runNextReady();
+ verify(mHistoryTracker).addResults(anyCollection(), eq(2000L));
+ }
+
+ @Test
+ public void testHistory_doubleTap() {
+ // When trying to classify single taps, we don't immediately add results to history.
+ mBrightLineFalsingManager.isFalseTap(false);
+ mGestureCompleteListener.onGestureComplete(1000);
+ // Before checking for double tap, we may check for single-tap on the second gesture.
+ mBrightLineFalsingManager.isFalseTap(false);
+ mBrightLineFalsingManager.isFalseDoubleTap();
+ mGestureCompleteListener.onGestureComplete(2000);
+
+ // Double tap is immediately added to history. Single tap is never added.
+ verify(mHistoryTracker).addResults(anyCollection(), eq(2000L));
+
+ assertThat(mFakeExecutor.numPending()).isEqualTo(0);
}
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/classifier/FalsingCollectorImplTest.java b/packages/SystemUI/tests/src/com/android/systemui/classifier/FalsingCollectorImplTest.java
index af5e789..23ef865 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/classifier/FalsingCollectorImplTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/classifier/FalsingCollectorImplTest.java
@@ -17,12 +17,15 @@
package com.android.systemui.classifier;
import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.argThat;
+import static org.mockito.Mockito.inOrder;
import static org.mockito.Mockito.never;
import static org.mockito.Mockito.reset;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
import android.testing.AndroidTestingRunner;
+import android.view.MotionEvent;
import androidx.test.filters.SmallTest;
@@ -38,6 +41,7 @@
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.ArgumentCaptor;
+import org.mockito.InOrder;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
@@ -66,7 +70,6 @@
mKeyguardUpdateMonitor, mProximitySensor, mStatusBarStateController);
}
-
@Test
public void testRegisterSensor() {
mFalsingCollector.onScreenTurningOn();
@@ -110,7 +113,6 @@
@Test
public void testUnregisterSensor_StateTransition() {
-
ArgumentCaptor<StatusBarStateController.StateListener> stateListenerArgumentCaptor =
ArgumentCaptor.forClass(StatusBarStateController.StateListener.class);
verify(mStatusBarStateController).addCallback(stateListenerArgumentCaptor.capture());
@@ -120,4 +122,37 @@
stateListenerArgumentCaptor.getValue().onStateChanged(StatusBarState.SHADE);
verify(mProximitySensor).unregister(any(ThresholdSensor.Listener.class));
}
+
+ @Test
+ public void testPassThroughGesture() {
+ MotionEvent down = MotionEvent.obtain(0, 0, MotionEvent.ACTION_DOWN, 0, 0, 0);
+ MotionEvent up = MotionEvent.obtain(0, 0, MotionEvent.ACTION_UP, 0, 0, 0);
+
+ // Nothing passed initially
+ mFalsingCollector.onTouchEvent(down);
+ verify(mFalsingDataProvider, never()).onMotionEvent(any(MotionEvent.class));
+
+ // Up event flushes the down event.
+ mFalsingCollector.onTouchEvent(up);
+ InOrder orderedCalls = inOrder(mFalsingDataProvider);
+ // We can't simply use "eq" or similar because the collector makes a copy of "down".
+ orderedCalls.verify(mFalsingDataProvider).onMotionEvent(
+ argThat(argument -> argument.getActionMasked() == MotionEvent.ACTION_DOWN));
+ orderedCalls.verify(mFalsingDataProvider).onMotionEvent(up);
+ }
+
+ @Test
+ public void testAvoidGesture() {
+ MotionEvent down = MotionEvent.obtain(0, 0, MotionEvent.ACTION_DOWN, 0, 0, 0);
+ MotionEvent up = MotionEvent.obtain(0, 0, MotionEvent.ACTION_DOWN, 0, 0, 0);
+
+ // Nothing passed initially
+ mFalsingCollector.onTouchEvent(down);
+ verify(mFalsingDataProvider, never()).onMotionEvent(any(MotionEvent.class));
+
+ mFalsingCollector.avoidGesture();
+ // Up event would flush, but we were told to avoid.
+ mFalsingCollector.onTouchEvent(up);
+ verify(mFalsingDataProvider, never()).onMotionEvent(any(MotionEvent.class));
+ }
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/screenshot/ImageExporterTest.java b/packages/SystemUI/tests/src/com/android/systemui/screenshot/ImageExporterTest.java
new file mode 100644
index 0000000..f566880
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/screenshot/ImageExporterTest.java
@@ -0,0 +1,180 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.screenshot;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertTrue;
+
+import static java.nio.charset.StandardCharsets.US_ASCII;
+
+import android.content.ContentResolver;
+import android.content.ContentValues;
+import android.content.Context;
+import android.graphics.Bitmap;
+import android.graphics.Bitmap.CompressFormat;
+import android.graphics.BitmapFactory;
+import android.graphics.Canvas;
+import android.graphics.Color;
+import android.graphics.Paint;
+import android.net.Uri;
+import android.os.Build;
+import android.os.ParcelFileDescriptor;
+import android.provider.MediaStore;
+import android.testing.AndroidTestingRunner;
+
+import androidx.exifinterface.media.ExifInterface;
+import androidx.test.filters.MediumTest;
+import androidx.test.platform.app.InstrumentationRegistry;
+
+import com.android.systemui.SysuiTestCase;
+
+import com.google.common.util.concurrent.ListenableFuture;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import java.io.ByteArrayInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.time.LocalDateTime;
+import java.time.ZoneId;
+import java.time.ZonedDateTime;
+import java.util.concurrent.ExecutionException;
+import java.util.concurrent.Executor;
+
+@RunWith(AndroidTestingRunner.class)
+@MediumTest // file I/O
+public class ImageExporterTest extends SysuiTestCase {
+
+ /** Executes directly in the caller's thread */
+ private static final Executor DIRECT_EXECUTOR = Runnable::run;
+ private static final byte[] EXIF_FILE_TAG = "Exif\u0000\u0000".getBytes(US_ASCII);
+
+ private static final ZonedDateTime CAPTURE_TIME =
+ ZonedDateTime.of(LocalDateTime.of(2020, 12, 15, 13, 15), ZoneId.of("EST"));
+
+ @Test
+ public void testImageFilename() {
+ assertEquals("image file name", "Screenshot_20201215-131500.png",
+ ImageExporter.createFilename(CAPTURE_TIME, CompressFormat.PNG));
+ }
+
+ @Test
+ public void testUpdateExifAttributes_timeZoneUTC() throws IOException {
+ ExifInterface exifInterface = new ExifInterface(new ByteArrayInputStream(EXIF_FILE_TAG),
+ ExifInterface.STREAM_TYPE_EXIF_DATA_ONLY);
+
+ ImageExporter.updateExifAttributes(exifInterface, 100, 100,
+ ZonedDateTime.of(LocalDateTime.of(2020, 12, 15, 18, 15), ZoneId.of("UTC")));
+
+ assertEquals("Exif " + ExifInterface.TAG_OFFSET_TIME_ORIGINAL, "+00:00",
+ exifInterface.getAttribute(ExifInterface.TAG_OFFSET_TIME_ORIGINAL));
+ assertEquals("Exif " + ExifInterface.TAG_OFFSET_TIME_ORIGINAL, "+00:00",
+ exifInterface.getAttribute(ExifInterface.TAG_OFFSET_TIME_DIGITIZED));
+ }
+
+ @Test
+ public void testImageExport() throws ExecutionException, InterruptedException, IOException {
+ Context context = InstrumentationRegistry.getInstrumentation().getContext();
+ ContentResolver contentResolver = context.getContentResolver();
+ ImageExporter exporter = new ImageExporter(contentResolver);
+
+ Bitmap original = createCheckerBitmap(10, 10, 10);
+
+ ListenableFuture<Uri> direct = exporter.export(DIRECT_EXECUTOR, original, CAPTURE_TIME);
+ assertTrue("future should be done", direct.isDone());
+ assertFalse("future should not be canceled", direct.isCancelled());
+ Uri result = direct.get();
+
+ assertNotNull("Uri should not be null", result);
+ Bitmap decoded = null;
+ try (InputStream in = contentResolver.openInputStream(result)) {
+ decoded = BitmapFactory.decodeStream(in);
+ assertNotNull("decoded image should not be null", decoded);
+ assertTrue("original and decoded image should be identical", original.sameAs(decoded));
+
+ try (ParcelFileDescriptor pfd = contentResolver.openFile(result, "r", null)) {
+ assertNotNull(pfd);
+ ExifInterface exifInterface = new ExifInterface(pfd.getFileDescriptor());
+
+ assertEquals("Exif " + ExifInterface.TAG_SOFTWARE, "Android " + Build.DISPLAY,
+ exifInterface.getAttribute(ExifInterface.TAG_SOFTWARE));
+
+ assertEquals("Exif " + ExifInterface.TAG_IMAGE_WIDTH, 100,
+ exifInterface.getAttributeInt(ExifInterface.TAG_IMAGE_WIDTH, 0));
+ assertEquals("Exif " + ExifInterface.TAG_IMAGE_LENGTH, 100,
+ exifInterface.getAttributeInt(ExifInterface.TAG_IMAGE_LENGTH, 0));
+
+ assertEquals("Exif " + ExifInterface.TAG_DATETIME_ORIGINAL, "2020:12:15 13:15:00",
+ exifInterface.getAttribute(ExifInterface.TAG_DATETIME_ORIGINAL));
+ assertEquals("Exif " + ExifInterface.TAG_SUBSEC_TIME_ORIGINAL, "000",
+ exifInterface.getAttribute(ExifInterface.TAG_SUBSEC_TIME_ORIGINAL));
+ assertEquals("Exif " + ExifInterface.TAG_OFFSET_TIME_ORIGINAL, "-05:00",
+ exifInterface.getAttribute(ExifInterface.TAG_OFFSET_TIME_ORIGINAL));
+
+ assertEquals("Exif " + ExifInterface.TAG_DATETIME_DIGITIZED, "2020:12:15 13:15:00",
+ exifInterface.getAttribute(ExifInterface.TAG_DATETIME_DIGITIZED));
+ assertEquals("Exif " + ExifInterface.TAG_SUBSEC_TIME_DIGITIZED, "000",
+ exifInterface.getAttribute(ExifInterface.TAG_SUBSEC_TIME_DIGITIZED));
+ assertEquals("Exif " + ExifInterface.TAG_OFFSET_TIME_DIGITIZED, "-05:00",
+ exifInterface.getAttribute(ExifInterface.TAG_OFFSET_TIME_DIGITIZED));
+ }
+ } finally {
+ if (decoded != null) {
+ decoded.recycle();
+ }
+ contentResolver.delete(result, null);
+ }
+ }
+
+ @Test
+ public void testMediaStoreMetadata() {
+ ContentValues values = ImageExporter.createMetadata(CAPTURE_TIME, CompressFormat.PNG);
+ assertEquals("Pictures/Screenshots",
+ values.getAsString(MediaStore.MediaColumns.RELATIVE_PATH));
+ assertEquals("Screenshot_20201215-131500.png",
+ values.getAsString(MediaStore.MediaColumns.DISPLAY_NAME));
+ assertEquals("image/png", values.getAsString(MediaStore.MediaColumns.MIME_TYPE));
+ assertEquals(Long.valueOf(1608056100L),
+ values.getAsLong(MediaStore.MediaColumns.DATE_ADDED));
+ assertEquals(Long.valueOf(1608056100L),
+ values.getAsLong(MediaStore.MediaColumns.DATE_MODIFIED));
+ assertEquals(Integer.valueOf(1), values.getAsInteger(MediaStore.MediaColumns.IS_PENDING));
+ assertEquals(Long.valueOf(1608056100L + 86400L), // +1 day
+ values.getAsLong(MediaStore.MediaColumns.DATE_EXPIRES));
+ }
+
+ @SuppressWarnings("SameParameterValue")
+ private Bitmap createCheckerBitmap(int tileSize, int w, int h) {
+ Bitmap bitmap = Bitmap.createBitmap(w * tileSize, h * tileSize, Bitmap.Config.ARGB_8888);
+ Canvas c = new Canvas(bitmap);
+ Paint paint = new Paint();
+ paint.setStyle(Paint.Style.FILL);
+
+ for (int i = 0; i < h; i++) {
+ int top = i * tileSize;
+ for (int j = 0; j < w; j++) {
+ int left = j * tileSize;
+ paint.setColor(paint.getColor() == Color.WHITE ? Color.BLACK : Color.WHITE);
+ c.drawRect(left, top, left + tileSize, top + tileSize, paint);
+ }
+ }
+ return bitmap;
+ }
+}
diff --git a/services/core/java/com/android/server/ConnectivityService.java b/services/core/java/com/android/server/ConnectivityService.java
index 4e75a9e..1378776 100644
--- a/services/core/java/com/android/server/ConnectivityService.java
+++ b/services/core/java/com/android/server/ConnectivityService.java
@@ -3597,8 +3597,8 @@
private boolean isNetworkPotentialSatisfier(
@NonNull final NetworkAgentInfo candidate, @NonNull final NetworkRequestInfo nri) {
// listen requests won't keep up a network satisfying it. If this is not a multilayer
- // request, we can return immediately. For multilayer requests, we have to check to see if
- // any of the multilayer requests may have a potential satisfier.
+ // request, return immediately. For multilayer requests, check to see if any of the
+ // multilayer requests may have a potential satisfier.
if (!nri.isMultilayerRequest() && nri.mRequests.get(0).isListen()) {
return false;
}
@@ -8234,6 +8234,13 @@
final IBinder iCb = cb.asBinder();
final NetworkRequestInfo nri = cbInfo.mRequestInfo;
+ // Connectivity Diagnostics are meant to be used with a single network request. It would be
+ // confusing for these networks to change when an NRI is satisfied in another layer.
+ if (nri.isMultilayerRequest()) {
+ throw new IllegalArgumentException("Connectivity Diagnostics do not support multilayer "
+ + "network requests.");
+ }
+
// This means that the client registered the same callback multiple times. Do
// not override the previous entry, and exit silently.
if (mConnectivityDiagnosticsCallbacks.containsKey(iCb)) {
@@ -8260,7 +8267,8 @@
synchronized (mNetworkForNetId) {
for (int i = 0; i < mNetworkForNetId.size(); i++) {
final NetworkAgentInfo nai = mNetworkForNetId.valueAt(i);
- if (nai.satisfies(nri.request)) {
+ // Connectivity Diagnostics rejects multilayer requests at registration hence get(0)
+ if (nai.satisfies(nri.mRequests.get(0))) {
matchingNetworks.add(nai);
}
}
@@ -8388,7 +8396,8 @@
mConnectivityDiagnosticsCallbacks.entrySet()) {
final ConnectivityDiagnosticsCallbackInfo cbInfo = entry.getValue();
final NetworkRequestInfo nri = cbInfo.mRequestInfo;
- if (nai.satisfies(nri.request)) {
+ // Connectivity Diagnostics rejects multilayer requests at registration hence get(0).
+ if (nai.satisfies(nri.mRequests.get(0))) {
if (checkConnectivityDiagnosticsPermissions(
nri.mPid, nri.mUid, nai, cbInfo.mCallingPackageName)) {
results.add(entry.getValue().mCb);
diff --git a/services/core/java/com/android/server/DynamicSystemService.java b/services/core/java/com/android/server/DynamicSystemService.java
index 500e768..f2b63a6 100644
--- a/services/core/java/com/android/server/DynamicSystemService.java
+++ b/services/core/java/com/android/server/DynamicSystemService.java
@@ -236,4 +236,9 @@
throw new RuntimeException(e.toString());
}
}
+
+ @Override
+ public long suggestScratchSize() throws RemoteException {
+ return getGsiService().suggestScratchSize();
+ }
}
diff --git a/services/core/java/com/android/server/OWNERS b/services/core/java/com/android/server/OWNERS
index 046d927..8f1ca83 100644
--- a/services/core/java/com/android/server/OWNERS
+++ b/services/core/java/com/android/server/OWNERS
@@ -13,6 +13,9 @@
# Sensor Privacy
per-file SensorPrivacyService.java = file:platform/frameworks/native:/libs/sensorprivacy/OWNERS
+# ServiceWatcher
+per-file ServiceWatcher.java = sooniln@google.com
+
per-file *Alarm* = file:/apex/jobscheduler/OWNERS
per-file *AppOp* = file:/core/java/android/permission/OWNERS
per-file *Bluetooth* = file:/core/java/android/bluetooth/OWNERS
diff --git a/services/core/java/com/android/server/ServiceWatcher.java b/services/core/java/com/android/server/ServiceWatcher.java
index 3ccb6e5..c2d8fa2 100644
--- a/services/core/java/com/android/server/ServiceWatcher.java
+++ b/services/core/java/com/android/server/ServiceWatcher.java
@@ -26,6 +26,7 @@
import static android.content.pm.PackageManager.MATCH_SYSTEM_ONLY;
import android.annotation.BoolRes;
+import android.annotation.NonNull;
import android.annotation.Nullable;
import android.annotation.StringRes;
import android.annotation.UserIdInt;
@@ -53,6 +54,7 @@
import java.io.PrintWriter;
import java.util.List;
import java.util.Objects;
+import java.util.function.Predicate;
/**
* Maintains a binding to the best service that matches the given intent information. Bind and
@@ -68,6 +70,8 @@
private static final long RETRY_DELAY_MS = 15 * 1000;
+ private static final Predicate<ResolveInfo> DEFAULT_SERVICE_CHECK_PREDICATE = x -> true;
+
/** Function to run on binder interface. */
public interface BinderRunner {
/** Called to run client code with the binder. */
@@ -184,6 +188,7 @@
private final Context mContext;
private final Handler mHandler;
private final Intent mIntent;
+ private final Predicate<ResolveInfo> mServiceCheckPredicate;
private final PackageMonitor mPackageMonitor = new PackageMonitor() {
@Override
@@ -239,15 +244,24 @@
@Nullable OnBindRunner onBind, @Nullable Runnable onUnbind,
@BoolRes int enableOverlayResId, @StringRes int nonOverlayPackageResId) {
this(context, FgThread.getHandler(), action, onBind, onUnbind, enableOverlayResId,
- nonOverlayPackageResId);
+ nonOverlayPackageResId, DEFAULT_SERVICE_CHECK_PREDICATE);
}
public ServiceWatcher(Context context, Handler handler, String action,
@Nullable OnBindRunner onBind, @Nullable Runnable onUnbind,
@BoolRes int enableOverlayResId, @StringRes int nonOverlayPackageResId) {
+ this(context, handler, action, onBind, onUnbind, enableOverlayResId, nonOverlayPackageResId,
+ DEFAULT_SERVICE_CHECK_PREDICATE);
+ }
+
+ public ServiceWatcher(Context context, Handler handler, String action,
+ @Nullable OnBindRunner onBind, @Nullable Runnable onUnbind,
+ @BoolRes int enableOverlayResId, @StringRes int nonOverlayPackageResId,
+ @NonNull Predicate<ResolveInfo> serviceCheckPredicate) {
mContext = context;
mHandler = handler;
mIntent = new Intent(Objects.requireNonNull(action));
+ mServiceCheckPredicate = Objects.requireNonNull(serviceCheckPredicate);
Resources resources = context.getResources();
boolean enableOverlay = resources.getBoolean(enableOverlayResId);
@@ -269,9 +283,16 @@
* constraints.
*/
public boolean checkServiceResolves() {
- return !mContext.getPackageManager().queryIntentServicesAsUser(mIntent,
- MATCH_DIRECT_BOOT_AWARE | MATCH_DIRECT_BOOT_UNAWARE | MATCH_SYSTEM_ONLY,
- UserHandle.USER_SYSTEM).isEmpty();
+ List<ResolveInfo> resolveInfos = mContext.getPackageManager()
+ .queryIntentServicesAsUser(mIntent,
+ MATCH_DIRECT_BOOT_AWARE | MATCH_DIRECT_BOOT_UNAWARE | MATCH_SYSTEM_ONLY,
+ UserHandle.USER_SYSTEM);
+ for (ResolveInfo resolveInfo : resolveInfos) {
+ if (mServiceCheckPredicate.test(resolveInfo)) {
+ return true;
+ }
+ }
+ return false;
}
/**
@@ -320,6 +341,9 @@
GET_META_DATA | MATCH_DIRECT_BOOT_AUTO | MATCH_SYSTEM_ONLY,
mCurrentUserId);
for (ResolveInfo resolveInfo : resolveInfos) {
+ if (!mServiceCheckPredicate.test(resolveInfo)) {
+ continue;
+ }
ServiceInfo serviceInfo = new ServiceInfo(resolveInfo, mCurrentUserId);
if (serviceInfo.compareTo(bestServiceInfo) > 0) {
bestServiceInfo = serviceInfo;
diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java
index 1841d67..8cb9b0a 100644
--- a/services/core/java/com/android/server/am/ActivityManagerService.java
+++ b/services/core/java/com/android/server/am/ActivityManagerService.java
@@ -14052,18 +14052,25 @@
callerApp = mPidsSelfLocked.get(pid);
}
}
- // Check if the instrumentation of the process has the permission. This covers the usual
- // test started from the shell (which has the permission) case. This is needed for apps
- // targeting SDK level < S but we are also allowing for targetSdk S+ as a convenience to
- // avoid breaking a bunch of existing tests and asking them to adopt shell permissions to do
- // this.
+
if (callerApp != null) {
+ // Check if the instrumentation of the process has the permission. This covers the usual
+ // test started from the shell (which has the permission) case. This is needed for apps
+ // targeting SDK level < S but we are also allowing for targetSdk S+ as a convenience to
+ // avoid breaking a bunch of existing tests and asking them to adopt shell permissions
+ // to do this.
ActiveInstrumentation instrumentation = callerApp.getActiveInstrumentation();
if (instrumentation != null && checkPermission(
permission.BROADCAST_CLOSE_SYSTEM_DIALOGS, -1, instrumentation.mSourceUid)
== PERMISSION_GRANTED) {
return true;
}
+ // This is the notification trampoline use-case for example, where apps use Intent.ACSD
+ // to close the shade prior to starting an activity.
+ WindowProcessController wmApp = callerApp.getWindowProcessController();
+ if (wmApp.canCloseSystemDialogsByToken()) {
+ return true;
+ }
}
return false;
}
diff --git a/services/core/java/com/android/server/am/ServiceRecord.java b/services/core/java/com/android/server/am/ServiceRecord.java
index e129561..d9c83da 100644
--- a/services/core/java/com/android/server/am/ServiceRecord.java
+++ b/services/core/java/com/android/server/am/ServiceRecord.java
@@ -749,9 +749,15 @@
// There are other callbacks in the queue, let's just update the originating
// token
if (mIsAllowedBgActivityStartsByStart) {
- mAppForAllowingBgActivityStartsByStart
- .addOrUpdateAllowBackgroundActivityStartsToken(
- this, getExclusiveOriginatingToken());
+ // mAppForAllowingBgActivityStartsByStart can be null here for example
+ // if get 2 calls to allowBgActivityStartsOnServiceStart() without a
+ // process attached to this ServiceRecord, so we need to perform a null
+ // check here.
+ if (mAppForAllowingBgActivityStartsByStart != null) {
+ mAppForAllowingBgActivityStartsByStart
+ .addOrUpdateAllowBackgroundActivityStartsToken(
+ this, getExclusiveOriginatingToken());
+ }
} else {
Slog.wtf(TAG,
"Service callback to revoke bg activity starts by service "
diff --git a/services/core/java/com/android/server/biometrics/BiometricService.java b/services/core/java/com/android/server/biometrics/BiometricService.java
index 75e1938..a81abcd 100644
--- a/services/core/java/com/android/server/biometrics/BiometricService.java
+++ b/services/core/java/com/android/server/biometrics/BiometricService.java
@@ -608,8 +608,9 @@
}
@Override
- public void registerAuthenticator(int id, int modality, @Authenticators.Types int strength,
- IBiometricAuthenticator authenticator) {
+ public synchronized void registerAuthenticator(int id, int modality,
+ @Authenticators.Types int strength,
+ @NonNull IBiometricAuthenticator authenticator) {
checkInternalPermission();
Slog.d(TAG, "Registering ID: " + id
diff --git a/services/core/java/com/android/server/input/InputManagerService.java b/services/core/java/com/android/server/input/InputManagerService.java
index bff81e6..71fcd1d 100644
--- a/services/core/java/com/android/server/input/InputManagerService.java
+++ b/services/core/java/com/android/server/input/InputManagerService.java
@@ -161,6 +161,9 @@
"com.snapchat.android" // b/173297887
};
+ /** TODO(b/169067926): Remove this. */
+ private static final boolean UNTRUSTED_TOUCHES_TOAST = false;
+
// Pointer to native input manager service object.
private final long mPtr;
@@ -2307,7 +2310,8 @@
// Native callback
private void notifyUntrustedTouch(String packageName) {
// TODO(b/169067926): Remove toast after gathering feedback on dogfood.
- if (ArrayUtils.contains(PACKAGE_BLOCKLIST_FOR_UNTRUSTED_TOUCHES_TOAST, packageName)) {
+ if (!UNTRUSTED_TOUCHES_TOAST || ArrayUtils.contains(
+ PACKAGE_BLOCKLIST_FOR_UNTRUSTED_TOUCHES_TOAST, packageName)) {
Log.i(TAG, "Suppressing untrusted touch toast for " + packageName);
return;
}
diff --git a/services/core/java/com/android/server/location/LocationManagerService.java b/services/core/java/com/android/server/location/LocationManagerService.java
index 9068287..372bcee 100644
--- a/services/core/java/com/android/server/location/LocationManagerService.java
+++ b/services/core/java/com/android/server/location/LocationManagerService.java
@@ -52,8 +52,8 @@
import android.location.IGnssAntennaInfoListener;
import android.location.IGnssMeasurementsListener;
import android.location.IGnssNavigationMessageListener;
+import android.location.IGnssNmeaListener;
import android.location.IGnssStatusListener;
-import android.location.IGpsGeofenceHardware;
import android.location.ILocationCallback;
import android.location.ILocationListener;
import android.location.ILocationManager;
@@ -64,6 +64,7 @@
import android.location.LocationProvider;
import android.location.LocationRequest;
import android.location.LocationTime;
+import android.location.ProviderProperties;
import android.location.util.identity.CallerIdentity;
import android.os.Binder;
import android.os.Bundle;
@@ -80,17 +81,19 @@
import android.util.Log;
import com.android.internal.annotations.GuardedBy;
-import com.android.internal.location.ProviderProperties;
import com.android.internal.util.DumpUtils;
import com.android.internal.util.Preconditions;
import com.android.server.LocalServices;
import com.android.server.SystemService;
import com.android.server.location.geofence.GeofenceManager;
import com.android.server.location.geofence.GeofenceProxy;
+import com.android.server.location.gnss.GnssConfiguration;
import com.android.server.location.gnss.GnssManagerService;
+import com.android.server.location.gnss.hal.GnssNative;
import com.android.server.location.injector.AlarmHelper;
import com.android.server.location.injector.AppForegroundHelper;
import com.android.server.location.injector.AppOpsHelper;
+import com.android.server.location.injector.EmergencyHelper;
import com.android.server.location.injector.Injector;
import com.android.server.location.injector.LocationAttributionHelper;
import com.android.server.location.injector.LocationEventLog;
@@ -102,6 +105,7 @@
import com.android.server.location.injector.SystemAlarmHelper;
import com.android.server.location.injector.SystemAppForegroundHelper;
import com.android.server.location.injector.SystemAppOpsHelper;
+import com.android.server.location.injector.SystemEmergencyHelper;
import com.android.server.location.injector.SystemLocationPermissionsHelper;
import com.android.server.location.injector.SystemLocationPowerSaveModeHelper;
import com.android.server.location.injector.SystemScreenInteractiveHelper;
@@ -367,8 +371,10 @@
// initialize gnss last because it has no awareness of boot phases and blindly assumes that
// all other location providers are loaded at initialization
- if (GnssManagerService.isGnssSupported()) {
- mGnssManagerService = new GnssManagerService(mContext, mInjector);
+ if (GnssNative.isSupported()) {
+ GnssConfiguration gnssConfiguration = new GnssConfiguration(mContext);
+ GnssNative gnssNative = GnssNative.create(mInjector, gnssConfiguration);
+ mGnssManagerService = new GnssManagerService(mContext, mInjector, gnssNative);
mGnssManagerService.onSystemReady();
LocationProviderManager gnssManager = new LocationProviderManager(mContext, mInjector,
@@ -390,13 +396,11 @@
}
// bind to gnss geofence proxy
- if (GnssManagerService.isGnssSupported()) {
- IGpsGeofenceHardware gpsGeofenceHardware = mGnssManagerService.getGpsGeofenceProxy();
- if (gpsGeofenceHardware != null) {
- GeofenceProxy provider = GeofenceProxy.createAndBind(mContext, gpsGeofenceHardware);
- if (provider == null) {
- Log.e(TAG, "unable to bind to GeofenceProxy");
- }
+ if (mGnssManagerService != null) {
+ GeofenceProxy provider = GeofenceProxy.createAndBind(mContext,
+ mGnssManagerService.getGnssGeofenceProxy());
+ if (provider == null) {
+ Log.e(TAG, "unable to bind to GeofenceProxy");
}
}
@@ -414,7 +418,7 @@
Boolean.parseBoolean(fragments[5]) /* supportsAltitude */,
Boolean.parseBoolean(fragments[6]) /* supportsSpeed */,
Boolean.parseBoolean(fragments[7]) /* supportsBearing */,
- Integer.parseInt(fragments[8]) /* powerRequirement */,
+ Integer.parseInt(fragments[8]) /* powerUsage */,
Integer.parseInt(fragments[9]) /* accuracy */);
getOrAddLocationProviderManager(name).setMockProvider(
new MockLocationProvider(properties, CallerIdentity.fromContext(mContext)));
@@ -516,6 +520,11 @@
}
@Override
+ public boolean hasProvider(String provider) {
+ return getLocationProviderManager(provider) != null;
+ }
+
+ @Override
public List<String> getAllProviders() {
ArrayList<String> providers = new ArrayList<>(mProviderManagers.size());
for (LocationProviderManager manager : mProviderManagers) {
@@ -859,6 +868,21 @@
}
@Override
+ public void registerGnssNmeaCallback(IGnssNmeaListener listener, String packageName,
+ String attributionTag) {
+ if (mGnssManagerService != null) {
+ mGnssManagerService.registerGnssNmeaCallback(listener, packageName, attributionTag);
+ }
+ }
+
+ @Override
+ public void unregisterGnssNmeaCallback(IGnssNmeaListener listener) {
+ if (mGnssManagerService != null) {
+ mGnssManagerService.unregisterGnssNmeaCallback(listener);
+ }
+ }
+
+ @Override
public void addGnssMeasurementsListener(@Nullable GnssMeasurementRequest request,
IGnssMeasurementsListener listener, String packageName, String attributionTag) {
if (mGnssManagerService != null) {
@@ -883,8 +907,8 @@
}
@Override
- public long getGnssCapabilities() {
- return mGnssManagerService == null ? GnssCapabilities.INVALID_CAPABILITIES
+ public GnssCapabilities getGnssCapabilities() {
+ return mGnssManagerService == null ? new GnssCapabilities.Builder().build()
: mGnssManagerService.getGnssCapabilities();
}
@@ -944,11 +968,10 @@
}
@Override
- public ProviderProperties getProviderProperties(String providerName) {
- LocationProviderManager manager = getLocationProviderManager(providerName);
- if (manager == null) {
- return null;
- }
+ public ProviderProperties getProviderProperties(String provider) {
+ LocationProviderManager manager = getLocationProviderManager(provider);
+ Preconditions.checkArgument(manager != null,
+ "provider \"" + provider + "\" does not exist");
return manager.getProperties();
}
@@ -1285,8 +1308,10 @@
private static class SystemInjector implements Injector {
- private final LocationEventLog mLocationEventLog;
+ private final Context mContext;
+
private final UserInfoHelper mUserInfoHelper;
+ private final LocationEventLog mLocationEventLog;
private final AlarmHelper mAlarmHelper;
private final SystemAppOpsHelper mAppOpsHelper;
private final SystemLocationPermissionsHelper mLocationPermissionsHelper;
@@ -1297,9 +1322,19 @@
private final LocationAttributionHelper mLocationAttributionHelper;
private final LocationUsageLogger mLocationUsageLogger;
+ // lazily instantiated since they may not always be used
+
+ @GuardedBy("this")
+ private @Nullable SystemEmergencyHelper mEmergencyCallHelper;
+
+ @GuardedBy("this")
+ private boolean mSystemReady;
+
SystemInjector(Context context, UserInfoHelper userInfoHelper) {
- mLocationEventLog = new LocationEventLog();
+ mContext = context;
+
mUserInfoHelper = userInfoHelper;
+ mLocationEventLog = new LocationEventLog();
mAlarmHelper = new SystemAlarmHelper(context);
mAppOpsHelper = new SystemAppOpsHelper(context);
mLocationPermissionsHelper = new SystemLocationPermissionsHelper(context,
@@ -1313,13 +1348,19 @@
mLocationUsageLogger = new LocationUsageLogger();
}
- void onSystemReady() {
+ synchronized void onSystemReady() {
mAppOpsHelper.onSystemReady();
mLocationPermissionsHelper.onSystemReady();
mSettingsHelper.onSystemReady();
mAppForegroundHelper.onSystemReady();
mLocationPowerSaveModeHelper.onSystemReady();
mScreenInteractiveHelper.onSystemReady();
+
+ if (mEmergencyCallHelper != null) {
+ mEmergencyCallHelper.onSystemReady();
+ }
+
+ mSystemReady = true;
}
@Override
@@ -1353,11 +1394,6 @@
}
@Override
- public LocationUsageLogger getLocationUsageLogger() {
- return mLocationUsageLogger;
- }
-
- @Override
public LocationPowerSaveModeHelper getLocationPowerSaveModeHelper() {
return mLocationPowerSaveModeHelper;
}
@@ -1373,8 +1409,25 @@
}
@Override
+ public synchronized EmergencyHelper getEmergencyHelper() {
+ if (mEmergencyCallHelper == null) {
+ mEmergencyCallHelper = new SystemEmergencyHelper(mContext);
+ if (mSystemReady) {
+ mEmergencyCallHelper.onSystemReady();
+ }
+ }
+
+ return mEmergencyCallHelper;
+ }
+
+ @Override
public LocationEventLog getLocationEventLog() {
return mLocationEventLog;
}
+
+ @Override
+ public LocationUsageLogger getLocationUsageLogger() {
+ return mLocationUsageLogger;
+ }
}
}
diff --git a/services/core/java/com/android/server/location/gnss/GnssAntennaInfoProvider.java b/services/core/java/com/android/server/location/gnss/GnssAntennaInfoProvider.java
index 9961d27..e9f79efb 100644
--- a/services/core/java/com/android/server/location/gnss/GnssAntennaInfoProvider.java
+++ b/services/core/java/com/android/server/location/gnss/GnssAntennaInfoProvider.java
@@ -20,12 +20,12 @@
import static com.android.server.location.gnss.GnssManagerService.TAG;
import android.location.GnssAntennaInfo;
+import android.location.GnssCapabilities;
import android.location.IGnssAntennaInfoListener;
import android.location.util.identity.CallerIdentity;
import android.util.Log;
-import com.android.internal.annotations.VisibleForTesting;
-import com.android.internal.util.Preconditions;
+import com.android.server.location.gnss.hal.GnssNative;
import com.android.server.location.injector.Injector;
import java.util.Collection;
@@ -35,23 +35,22 @@
* Provides GNSS antenna information to clients.
*/
public class GnssAntennaInfoProvider extends
- GnssListenerMultiplexer<Void, IGnssAntennaInfoListener, Void> {
+ GnssListenerMultiplexer<Void, IGnssAntennaInfoListener, Void> implements
+ GnssNative.BaseCallbacks, GnssNative.AntennaInfoCallbacks {
- private final GnssAntennaInfoProviderNative mNative;
+ private final GnssNative mGnssNative;
- public GnssAntennaInfoProvider(Injector injector) {
- this(injector, new GnssAntennaInfoProviderNative());
- }
-
- @VisibleForTesting
- public GnssAntennaInfoProvider(Injector injector, GnssAntennaInfoProviderNative aNative) {
+ public GnssAntennaInfoProvider(Injector injector, GnssNative gnssNative) {
super(injector);
- mNative = aNative;
+ mGnssNative = gnssNative;
+
+ mGnssNative.addBaseCallbacks(this);
+ mGnssNative.addAntennaInfoCallbacks(this);
}
@Override
protected boolean isServiceSupported() {
- return mNative.isAntennaInfoSupported();
+ return mGnssNative.isAntennaInfoListeningSupported();
}
@Override
@@ -62,9 +61,7 @@
@Override
protected boolean registerWithService(Void ignored,
Collection<GnssListenerRegistration> registrations) {
- Preconditions.checkState(mNative.isAntennaInfoSupported());
-
- if (mNative.startAntennaInfoListening()) {
+ if (mGnssNative.startAntennaInfoListening()) {
if (D) {
Log.d(TAG, "starting gnss antenna info");
}
@@ -77,7 +74,7 @@
@Override
protected void unregisterWithService() {
- if (mNative.stopAntennaInfoListening()) {
+ if (mGnssNative.stopAntennaInfoListening()) {
if (D) {
Log.d(TAG, "stopping gnss antenna info");
}
@@ -86,39 +83,19 @@
}
}
- /**
- * Called by GnssLocationProvider.
- */
- public void onGnssAntennaInfoAvailable(List<GnssAntennaInfo> gnssAntennaInfos) {
- deliverToListeners((listener) -> {
- listener.onGnssAntennaInfoReceived(gnssAntennaInfos);
+ @Override
+ public void onHalRestarted() {
+ resetService();
+ }
+
+ @Override
+ public void onCapabilitiesChanged(GnssCapabilities oldCapabilities,
+ GnssCapabilities newCapabilities) {}
+
+ @Override
+ public void onReportAntennaInfo(List<GnssAntennaInfo> antennaInfos) {
+ deliverToListeners(listener -> {
+ listener.onGnssAntennaInfoReceived(antennaInfos);
});
}
-
- /**
- * Wrapper class for native methods. This is mocked for testing.
- */
- @VisibleForTesting
- public static class GnssAntennaInfoProviderNative {
-
- public boolean isAntennaInfoSupported() {
- return native_is_antenna_info_supported();
- }
-
- /** Start antenna info listening. */
- public boolean startAntennaInfoListening() {
- return native_start_antenna_info_listening();
- }
-
- /** Stop antenna info listening. */
- public boolean stopAntennaInfoListening() {
- return native_stop_antenna_info_listening();
- }
- }
-
- static native boolean native_is_antenna_info_supported();
-
- static native boolean native_start_antenna_info_listening();
-
- static native boolean native_stop_antenna_info_listening();
}
diff --git a/services/core/java/com/android/server/location/gnss/GnssCapabilitiesProvider.java b/services/core/java/com/android/server/location/gnss/GnssCapabilitiesProvider.java
deleted file mode 100644
index 1c4fb10..0000000
--- a/services/core/java/com/android/server/location/gnss/GnssCapabilitiesProvider.java
+++ /dev/null
@@ -1,127 +0,0 @@
-/*
- * Copyright (C) 2020 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.server.location.gnss;
-
-import android.location.GnssCapabilities;
-import android.util.Log;
-
-import com.android.internal.annotations.GuardedBy;
-
-/**
- * Provides GNSS capabilities supported by the GNSS HAL implementation.
- */
-public class GnssCapabilitiesProvider {
- private static final String TAG = "GnssCapabilitiesProvider";
- private static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG);
-
- private static final long GNSS_CAPABILITIES_TOP_HAL =
- GnssCapabilities.LOW_POWER_MODE | GnssCapabilities.SATELLITE_BLOCKLIST
- | GnssCapabilities.GEOFENCING | GnssCapabilities.MEASUREMENTS
- | GnssCapabilities.NAV_MESSAGES;
-
- private static final long GNSS_CAPABILITIES_SUB_HAL_MEASUREMENT_CORRECTIONS =
- GnssCapabilities.MEASUREMENT_CORRECTIONS
- | GnssCapabilities.MEASUREMENT_CORRECTIONS_LOS_SATS
- | GnssCapabilities.MEASUREMENT_CORRECTIONS_EXCESS_PATH_LENGTH
- | GnssCapabilities.MEASUREMENT_CORRECTIONS_REFLECTING_PLANE;
-
- // Capabilities in {@link android.location.GnssCapabilities} supported by GNSS chipset.
- @GuardedBy("this")
- private long mGnssCapabilities;
-
- /**
- * Returns the capabilities supported by the GNSS chipset.
- *
- * <p>The capabilities are described in {@link android.location.GnssCapabilities} and
- * their integer values correspond to the bit positions in the returned {@code long} value.
- */
- public long getGnssCapabilities() {
- synchronized (this) {
- return mGnssCapabilities;
- }
- }
-
- /**
- * Updates the general capabilities exposed through {@link android.location.GnssCapabilities}.
- */
- void setTopHalCapabilities(int topHalCapabilities) {
- long gnssCapabilities = 0;
- if (hasCapability(topHalCapabilities,
- GnssLocationProvider.GPS_CAPABILITY_LOW_POWER_MODE)) {
- gnssCapabilities |= GnssCapabilities.LOW_POWER_MODE;
- }
- if (hasCapability(topHalCapabilities,
- GnssLocationProvider.GPS_CAPABILITY_SATELLITE_BLOCKLIST)) {
- gnssCapabilities |= GnssCapabilities.SATELLITE_BLOCKLIST;
- }
- if (hasCapability(topHalCapabilities, GnssLocationProvider.GPS_CAPABILITY_GEOFENCING)) {
- gnssCapabilities |= GnssCapabilities.GEOFENCING;
- }
- if (hasCapability(topHalCapabilities, GnssLocationProvider.GPS_CAPABILITY_MEASUREMENTS)) {
- gnssCapabilities |= GnssCapabilities.MEASUREMENTS;
- }
- if (hasCapability(topHalCapabilities, GnssLocationProvider.GPS_CAPABILITY_NAV_MESSAGES)) {
- gnssCapabilities |= GnssCapabilities.NAV_MESSAGES;
- }
- if (hasCapability(topHalCapabilities, GnssLocationProvider.GPS_CAPABILITY_ANTENNA_INFO)) {
- gnssCapabilities |= GnssCapabilities.ANTENNA_INFO;
- }
-
- synchronized (this) {
- mGnssCapabilities &= ~GNSS_CAPABILITIES_TOP_HAL;
- mGnssCapabilities |= gnssCapabilities;
- if (DEBUG) {
- Log.d(TAG, "setTopHalCapabilities, mGnssCapabilities=0x" + Long.toHexString(
- mGnssCapabilities) + ", " + GnssCapabilities.of(mGnssCapabilities));
- }
- }
- }
-
- /**
- * Updates the measurement corrections related capabilities exposed through
- * {@link android.location.GnssCapabilities}.
- */
- void setSubHalMeasurementCorrectionsCapabilities(int measurementCorrectionsCapabilities) {
- long gnssCapabilities = GnssCapabilities.MEASUREMENT_CORRECTIONS;
- if (hasCapability(measurementCorrectionsCapabilities,
- GnssMeasurementCorrectionsProvider.CAPABILITY_LOS_SATS)) {
- gnssCapabilities |= GnssCapabilities.MEASUREMENT_CORRECTIONS_LOS_SATS;
- }
- if (hasCapability(measurementCorrectionsCapabilities,
- GnssMeasurementCorrectionsProvider.CAPABILITY_EXCESS_PATH_LENGTH)) {
- gnssCapabilities |= GnssCapabilities.MEASUREMENT_CORRECTIONS_EXCESS_PATH_LENGTH;
- }
- if (hasCapability(measurementCorrectionsCapabilities,
- GnssMeasurementCorrectionsProvider.CAPABILITY_REFLECTING_PLANE)) {
- gnssCapabilities |= GnssCapabilities.MEASUREMENT_CORRECTIONS_REFLECTING_PLANE;
- }
-
- synchronized (this) {
- mGnssCapabilities &= ~GNSS_CAPABILITIES_SUB_HAL_MEASUREMENT_CORRECTIONS;
- mGnssCapabilities |= gnssCapabilities;
- if (DEBUG) {
- Log.d(TAG, "setSubHalMeasurementCorrectionsCapabilities, mGnssCapabilities=0x"
- + Long.toHexString(mGnssCapabilities) + ", " + GnssCapabilities.of(
- mGnssCapabilities));
- }
- }
- }
-
- private static boolean hasCapability(int halCapabilities, int capability) {
- return (halCapabilities & capability) != 0;
- }
-}
diff --git a/services/core/java/com/android/server/location/gnss/GnssConfiguration.java b/services/core/java/com/android/server/location/gnss/GnssConfiguration.java
index 2628372..60b7447 100644
--- a/services/core/java/com/android/server/location/gnss/GnssConfiguration.java
+++ b/services/core/java/com/android/server/location/gnss/GnssConfiguration.java
@@ -31,7 +31,7 @@
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
-import java.util.ArrayList;
+import java.util.Arrays;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
@@ -48,7 +48,7 @@
* Instances of this class are not thread-safe and should either be used from a single thread
* or with external synchronization when used by multiple threads.
*/
-class GnssConfiguration {
+public class GnssConfiguration {
private static final String TAG = "GnssConfiguration";
private static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG);
@@ -98,13 +98,13 @@
/**
* Properties loaded from PROPERTIES_FILE.
*/
- private Properties mProperties;
+ private final Properties mProperties;
private int mEsExtensionSec = 0;
private final Context mContext;
- GnssConfiguration(Context context) {
+ public GnssConfiguration(Context context) {
mContext = context;
mProperties = new Properties();
}
@@ -120,7 +120,7 @@
* Returns the value of config parameter ES_EXTENSION_SEC. The value is range checked
* and constrained to min/max limits.
*/
- int getEsExtensionSec() {
+ public int getEsExtensionSec() {
return mEsExtensionSec;
}
@@ -168,8 +168,8 @@
* Returns the value of config parameter SUPL_ES or {@code defaultSuplEs} if no value is
* provided or if there is an error parsing the configured value.
*/
- int getSuplEs(int defaulSuplEs) {
- return getIntConfig(CONFIG_SUPL_ES, defaulSuplEs);
+ public int getSuplEs(int defaultSuplEs) {
+ return getIntConfig(CONFIG_SUPL_ES, defaultSuplEs);
}
/**
@@ -181,27 +181,21 @@
}
/**
- * Returns the list of proxy apps from the value of config parameter NFW_PROXY_APPS or
- * {@Collections.EMPTY_LIST} if no value is provided.
+ * Returns the list of proxy apps from the value of config parameter NFW_PROXY_APPS.
*/
List<String> getProxyApps() {
// Space separated list of Android proxy app package names.
String proxyAppsStr = mProperties.getProperty(CONFIG_NFW_PROXY_APPS);
if (TextUtils.isEmpty(proxyAppsStr)) {
- return Collections.EMPTY_LIST;
+ return Collections.emptyList();
}
String[] proxyAppsArray = proxyAppsStr.trim().split("\\s+");
if (proxyAppsArray.length == 0) {
- return Collections.EMPTY_LIST;
+ return Collections.emptyList();
}
- ArrayList proxyApps = new ArrayList(proxyAppsArray.length);
- for (String proxyApp : proxyAppsArray) {
- proxyApps.add(proxyApp);
- }
-
- return proxyApps;
+ return Arrays.asList(proxyAppsArray);
}
/**
diff --git a/services/core/java/com/android/server/location/gnss/GnssGeofenceProvider.java b/services/core/java/com/android/server/location/gnss/GnssGeofenceProvider.java
deleted file mode 100644
index 53883b9..0000000
--- a/services/core/java/com/android/server/location/gnss/GnssGeofenceProvider.java
+++ /dev/null
@@ -1,189 +0,0 @@
-/*
- * Copyright (C) 2020 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.server.location.gnss;
-
-import android.location.IGpsGeofenceHardware;
-import android.util.Log;
-import android.util.SparseArray;
-
-import com.android.internal.annotations.GuardedBy;
-import com.android.internal.annotations.VisibleForTesting;
-
-/**
- * Manages GNSS Geofence operations.
- */
-class GnssGeofenceProvider extends IGpsGeofenceHardware.Stub {
-
- private static final String TAG = "GnssGeofenceProvider";
- private static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG);
-
- /** Holds the parameters of a geofence. */
- private static class GeofenceEntry {
- public int geofenceId;
- public double latitude;
- public double longitude;
- public double radius;
- public int lastTransition;
- public int monitorTransitions;
- public int notificationResponsiveness;
- public int unknownTimer;
- public boolean paused;
- }
-
- private final Object mLock = new Object();
- @GuardedBy("mLock")
- private final GnssGeofenceProviderNative mNative;
- @GuardedBy("mLock")
- private final SparseArray<GeofenceEntry> mGeofenceEntries = new SparseArray<>();
-
- GnssGeofenceProvider() {
- this(new GnssGeofenceProviderNative());
- }
-
- @VisibleForTesting
- GnssGeofenceProvider(GnssGeofenceProviderNative gnssGeofenceProviderNative) {
- mNative = gnssGeofenceProviderNative;
- }
-
- void resumeIfStarted() {
- if (DEBUG) {
- Log.d(TAG, "resumeIfStarted");
- }
- synchronized (mLock) {
- for (int i = 0; i < mGeofenceEntries.size(); i++) {
- GeofenceEntry entry = mGeofenceEntries.valueAt(i);
- boolean added = mNative.addGeofence(entry.geofenceId, entry.latitude,
- entry.longitude,
- entry.radius,
- entry.lastTransition, entry.monitorTransitions,
- entry.notificationResponsiveness, entry.unknownTimer);
- if (added && entry.paused) {
- mNative.pauseGeofence(entry.geofenceId);
- }
- }
- }
- }
-
- @Override
- public boolean isHardwareGeofenceSupported() {
- 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) {
- synchronized (mLock) {
- boolean added = mNative.addGeofence(geofenceId, latitude, longitude, radius,
- lastTransition, monitorTransitions, notificationResponsiveness,
- unknownTimer);
- if (added) {
- GeofenceEntry entry = new GeofenceEntry();
- entry.geofenceId = geofenceId;
- entry.latitude = latitude;
- entry.longitude = longitude;
- entry.radius = radius;
- entry.lastTransition = lastTransition;
- entry.monitorTransitions = monitorTransitions;
- entry.notificationResponsiveness = notificationResponsiveness;
- entry.unknownTimer = unknownTimer;
- mGeofenceEntries.put(geofenceId, entry);
- }
- return added;
- }
- }
-
- @Override
- public boolean removeHardwareGeofence(int geofenceId) {
- synchronized (mLock) {
- boolean removed = mNative.removeGeofence(geofenceId);
- if (removed) {
- mGeofenceEntries.remove(geofenceId);
- }
- return removed;
- }
- }
-
- @Override
- public boolean pauseHardwareGeofence(int geofenceId) {
- synchronized (mLock) {
- boolean paused = mNative.pauseGeofence(geofenceId);
- if (paused) {
- GeofenceEntry entry = mGeofenceEntries.get(geofenceId);
- if (entry != null) {
- entry.paused = true;
- }
- }
- return paused;
- }
- }
-
- @Override
- public boolean resumeHardwareGeofence(int geofenceId, int monitorTransitions) {
- synchronized (mLock) {
- boolean resumed = mNative.resumeGeofence(geofenceId, monitorTransitions);
- if (resumed) {
- GeofenceEntry entry = mGeofenceEntries.get(geofenceId);
- if (entry != null) {
- entry.paused = false;
- entry.monitorTransitions = monitorTransitions;
- }
- }
- return resumed;
- }
- }
-
- @VisibleForTesting
- static class GnssGeofenceProviderNative {
- public boolean isGeofenceSupported() {
- return native_is_geofence_supported();
- }
-
- public boolean addGeofence(int geofenceId, double latitude, double longitude, double radius,
- int lastTransition, int monitorTransitions, int notificationResponsiveness,
- int unknownTimer) {
- return native_add_geofence(geofenceId, latitude, longitude, radius, lastTransition,
- monitorTransitions, notificationResponsiveness, unknownTimer);
- }
-
- public boolean removeGeofence(int geofenceId) {
- return native_remove_geofence(geofenceId);
- }
-
- public boolean resumeGeofence(int geofenceId, int transitions) {
- return native_resume_geofence(geofenceId, transitions);
- }
-
- public boolean pauseGeofence(int geofenceId) {
- return native_pause_geofence(geofenceId);
- }
- }
-
- private static native boolean native_is_geofence_supported();
-
- private static native boolean native_add_geofence(int geofenceId, double latitude,
- double longitude, double radius, int lastTransition, int monitorTransitions,
- int notificationResponsivenes, int unknownTimer);
-
- private static native boolean native_remove_geofence(int geofenceId);
-
- private static native boolean native_resume_geofence(int geofenceId, int transitions);
-
- private static native boolean native_pause_geofence(int geofenceId);
-}
diff --git a/services/core/java/com/android/server/location/gnss/GnssGeofenceProxy.java b/services/core/java/com/android/server/location/gnss/GnssGeofenceProxy.java
new file mode 100644
index 0000000..32a7952
--- /dev/null
+++ b/services/core/java/com/android/server/location/gnss/GnssGeofenceProxy.java
@@ -0,0 +1,148 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.location.gnss;
+
+import android.location.GnssCapabilities;
+import android.location.IGpsGeofenceHardware;
+import android.util.SparseArray;
+
+import com.android.internal.annotations.GuardedBy;
+import com.android.server.location.gnss.hal.GnssNative;
+
+/**
+ * Manages GNSS Geofence operations.
+ */
+class GnssGeofenceProxy extends IGpsGeofenceHardware.Stub implements GnssNative.BaseCallbacks {
+
+ /** Holds the parameters of a geofence. */
+ private static class GeofenceEntry {
+ public int geofenceId;
+ public double latitude;
+ public double longitude;
+ public double radius;
+ public int lastTransition;
+ public int monitorTransitions;
+ public int notificationResponsiveness;
+ public int unknownTimer;
+ public boolean paused;
+ }
+
+ private final Object mLock = new Object();
+
+ private final GnssNative mGnssNative;
+
+ @GuardedBy("mLock")
+ private final SparseArray<GeofenceEntry> mGeofenceEntries = new SparseArray<>();
+
+ GnssGeofenceProxy(GnssNative gnssNative) {
+ mGnssNative = gnssNative;
+
+ mGnssNative.addBaseCallbacks(this);
+ }
+
+ @Override
+ public boolean isHardwareGeofenceSupported() {
+ synchronized (mLock) {
+ return mGnssNative.isGeofencingSupported();
+ }
+ }
+
+ @Override
+ public boolean addCircularHardwareGeofence(int geofenceId, double latitude,
+ double longitude, double radius, int lastTransition, int monitorTransitions,
+ int notificationResponsiveness, int unknownTimer) {
+ synchronized (mLock) {
+ boolean added = mGnssNative.addGeofence(geofenceId, latitude, longitude, radius,
+ lastTransition, monitorTransitions, notificationResponsiveness,
+ unknownTimer);
+ if (added) {
+ GeofenceEntry entry = new GeofenceEntry();
+ entry.geofenceId = geofenceId;
+ entry.latitude = latitude;
+ entry.longitude = longitude;
+ entry.radius = radius;
+ entry.lastTransition = lastTransition;
+ entry.monitorTransitions = monitorTransitions;
+ entry.notificationResponsiveness = notificationResponsiveness;
+ entry.unknownTimer = unknownTimer;
+ mGeofenceEntries.put(geofenceId, entry);
+ }
+ return added;
+ }
+ }
+
+ @Override
+ public boolean removeHardwareGeofence(int geofenceId) {
+ synchronized (mLock) {
+ boolean removed = mGnssNative.removeGeofence(geofenceId);
+ if (removed) {
+ mGeofenceEntries.remove(geofenceId);
+ }
+ return removed;
+ }
+ }
+
+ @Override
+ public boolean pauseHardwareGeofence(int geofenceId) {
+ synchronized (mLock) {
+ boolean paused = mGnssNative.pauseGeofence(geofenceId);
+ if (paused) {
+ GeofenceEntry entry = mGeofenceEntries.get(geofenceId);
+ if (entry != null) {
+ entry.paused = true;
+ }
+ }
+ return paused;
+ }
+ }
+
+ @Override
+ public boolean resumeHardwareGeofence(int geofenceId, int monitorTransitions) {
+ synchronized (mLock) {
+ boolean resumed = mGnssNative.resumeGeofence(geofenceId, monitorTransitions);
+ if (resumed) {
+ GeofenceEntry entry = mGeofenceEntries.get(geofenceId);
+ if (entry != null) {
+ entry.paused = false;
+ entry.monitorTransitions = monitorTransitions;
+ }
+ }
+ return resumed;
+ }
+ }
+
+ @Override
+ public void onHalRestarted() {
+ synchronized (mLock) {
+ for (int i = 0; i < mGeofenceEntries.size(); i++) {
+ GeofenceEntry entry = mGeofenceEntries.valueAt(i);
+ boolean added = mGnssNative.addGeofence(entry.geofenceId, entry.latitude,
+ entry.longitude,
+ entry.radius,
+ entry.lastTransition, entry.monitorTransitions,
+ entry.notificationResponsiveness, entry.unknownTimer);
+ if (added && entry.paused) {
+ mGnssNative.pauseGeofence(entry.geofenceId);
+ }
+ }
+ }
+ }
+
+ @Override
+ public void onCapabilitiesChanged(GnssCapabilities oldCapabilities,
+ GnssCapabilities newCapabilities) {}
+}
diff --git a/services/core/java/com/android/server/location/gnss/GnssLocationProvider.java b/services/core/java/com/android/server/location/gnss/GnssLocationProvider.java
index 0c77c1e..afe7567 100644
--- a/services/core/java/com/android/server/location/gnss/GnssLocationProvider.java
+++ b/services/core/java/com/android/server/location/gnss/GnssLocationProvider.java
@@ -17,6 +17,28 @@
package com.android.server.location.gnss;
import static com.android.internal.util.ConcurrentUtils.DIRECT_EXECUTOR;
+import static com.android.server.location.gnss.hal.GnssNative.AGPS_REF_LOCATION_TYPE_GSM_CELLID;
+import static com.android.server.location.gnss.hal.GnssNative.AGPS_REF_LOCATION_TYPE_UMTS_CELLID;
+import static com.android.server.location.gnss.hal.GnssNative.AGPS_SETID_TYPE_IMSI;
+import static com.android.server.location.gnss.hal.GnssNative.AGPS_SETID_TYPE_MSISDN;
+import static com.android.server.location.gnss.hal.GnssNative.AGPS_SETID_TYPE_NONE;
+import static com.android.server.location.gnss.hal.GnssNative.GNSS_AIDING_TYPE_ALL;
+import static com.android.server.location.gnss.hal.GnssNative.GNSS_AIDING_TYPE_ALMANAC;
+import static com.android.server.location.gnss.hal.GnssNative.GNSS_AIDING_TYPE_CELLDB_INFO;
+import static com.android.server.location.gnss.hal.GnssNative.GNSS_AIDING_TYPE_EPHEMERIS;
+import static com.android.server.location.gnss.hal.GnssNative.GNSS_AIDING_TYPE_HEALTH;
+import static com.android.server.location.gnss.hal.GnssNative.GNSS_AIDING_TYPE_IONO;
+import static com.android.server.location.gnss.hal.GnssNative.GNSS_AIDING_TYPE_POSITION;
+import static com.android.server.location.gnss.hal.GnssNative.GNSS_AIDING_TYPE_RTI;
+import static com.android.server.location.gnss.hal.GnssNative.GNSS_AIDING_TYPE_SADATA;
+import static com.android.server.location.gnss.hal.GnssNative.GNSS_AIDING_TYPE_SVDIR;
+import static com.android.server.location.gnss.hal.GnssNative.GNSS_AIDING_TYPE_SVSTEER;
+import static com.android.server.location.gnss.hal.GnssNative.GNSS_AIDING_TYPE_TIME;
+import static com.android.server.location.gnss.hal.GnssNative.GNSS_AIDING_TYPE_UTC;
+import static com.android.server.location.gnss.hal.GnssNative.GNSS_POSITION_MODE_MS_ASSISTED;
+import static com.android.server.location.gnss.hal.GnssNative.GNSS_POSITION_MODE_MS_BASED;
+import static com.android.server.location.gnss.hal.GnssNative.GNSS_POSITION_MODE_STANDALONE;
+import static com.android.server.location.gnss.hal.GnssNative.GNSS_POSITION_RECURRENCE_PERIODIC;
import static java.util.concurrent.TimeUnit.MILLISECONDS;
@@ -28,21 +50,16 @@
import android.content.Intent;
import android.content.IntentFilter;
import android.database.ContentObserver;
-import android.hardware.location.GeofenceHardware;
-import android.hardware.location.GeofenceHardwareImpl;
import android.location.Criteria;
-import android.location.FusedBatchOptions;
-import android.location.GnssAntennaInfo;
-import android.location.GnssMeasurementsEvent;
-import android.location.GnssNavigationMessage;
+import android.location.GnssCapabilities;
import android.location.GnssStatus;
-import android.location.IGpsGeofenceHardware;
import android.location.INetInitiatedListener;
import android.location.Location;
import android.location.LocationListener;
import android.location.LocationManager;
import android.location.LocationRequest;
import android.location.LocationResult;
+import android.location.ProviderProperties;
import android.location.util.identity.CallerIdentity;
import android.os.AsyncTask;
import android.os.BatteryStats;
@@ -72,13 +89,12 @@
import com.android.internal.app.IBatteryStats;
import com.android.internal.location.GpsNetInitiatedHandler;
import com.android.internal.location.GpsNetInitiatedHandler.GpsNiNotification;
-import com.android.internal.location.ProviderProperties;
import com.android.internal.location.ProviderRequest;
-import com.android.internal.location.gnssmetrics.GnssMetrics;
import com.android.internal.util.FrameworkStatsLog;
import com.android.server.FgThread;
import com.android.server.location.gnss.GnssSatelliteBlocklistHelper.GnssSatelliteBlocklistCallback;
import com.android.server.location.gnss.NtpTimeHelper.InjectNtpTimeCallback;
+import com.android.server.location.gnss.hal.GnssNative;
import com.android.server.location.injector.Injector;
import com.android.server.location.provider.AbstractLocationProvider;
@@ -97,8 +113,10 @@
* {@hide}
*/
public class GnssLocationProvider extends AbstractLocationProvider implements
- InjectNtpTimeCallback,
- GnssSatelliteBlocklistCallback {
+ InjectNtpTimeCallback, GnssSatelliteBlocklistCallback, GnssNative.BaseCallbacks,
+ GnssNative.LocationCallbacks, GnssNative.SvStatusCallbacks, GnssNative.AGpsCallbacks,
+ GnssNative.PsdsCallbacks, GnssNative.NotificationCallbacks,
+ GnssNative.LocationRequestCallbacks, GnssNative.TimeCallbacks {
private static final String TAG = "GnssLocationProvider";
@@ -113,104 +131,20 @@
/* supportAltitude = */true,
/* supportsSpeed = */true,
/* supportsBearing = */true,
- Criteria.POWER_HIGH,
- Criteria.ACCURACY_FINE);
-
- // these need to match GnssPositionMode enum in IGnss.hal
- private static final int GPS_POSITION_MODE_STANDALONE = 0;
- private static final int GPS_POSITION_MODE_MS_BASED = 1;
- private static final int GPS_POSITION_MODE_MS_ASSISTED = 2;
-
- // these need to match GnssPositionRecurrence enum in IGnss.hal
- private static final int GPS_POSITION_RECURRENCE_PERIODIC = 0;
- private static final int GPS_POSITION_RECURRENCE_SINGLE = 1;
-
- // these need to match GnssStatusValue enum in IGnssCallback.hal
- private static final int GPS_STATUS_NONE = 0;
- private static final int GPS_STATUS_SESSION_BEGIN = 1;
- private static final int GPS_STATUS_SESSION_END = 2;
- private static final int GPS_STATUS_ENGINE_ON = 3;
- private static final int GPS_STATUS_ENGINE_OFF = 4;
-
- // these need to match GnssLocationFlags enum in types.hal
- private static final int LOCATION_INVALID = 0;
- private static final int LOCATION_HAS_LAT_LONG = 1;
- private static final int LOCATION_HAS_ALTITUDE = 2;
- private static final int LOCATION_HAS_SPEED = 4;
- private static final int LOCATION_HAS_BEARING = 8;
- private static final int LOCATION_HAS_HORIZONTAL_ACCURACY = 16;
- private static final int LOCATION_HAS_VERTICAL_ACCURACY = 32;
- private static final int LOCATION_HAS_SPEED_ACCURACY = 64;
- private static final int LOCATION_HAS_BEARING_ACCURACY = 128;
-
- // these need to match ElapsedRealtimeFlags enum in types.hal
- private static final int ELAPSED_REALTIME_HAS_TIMESTAMP_NS = 1;
- private static final int ELAPSED_REALTIME_HAS_TIME_UNCERTAINTY_NS = 2;
-
- // IMPORTANT - the GPS_DELETE_* symbols here must match GnssAidingData enum in IGnss.hal
- private static final int GPS_DELETE_EPHEMERIS = 0x0001;
- private static final int GPS_DELETE_ALMANAC = 0x0002;
- private static final int GPS_DELETE_POSITION = 0x0004;
- private static final int GPS_DELETE_TIME = 0x0008;
- private static final int GPS_DELETE_IONO = 0x0010;
- private static final int GPS_DELETE_UTC = 0x0020;
- private static final int GPS_DELETE_HEALTH = 0x0040;
- private static final int GPS_DELETE_SVDIR = 0x0080;
- private static final int GPS_DELETE_SVSTEER = 0x0100;
- private static final int GPS_DELETE_SADATA = 0x0200;
- private static final int GPS_DELETE_RTI = 0x0400;
- private static final int GPS_DELETE_CELLDB_INFO = 0x8000;
- private static final int GPS_DELETE_ALL = 0xFFFF;
-
- // The GPS_CAPABILITY_* flags must match Capabilities enum in IGnssCallback.hal
- private static final int GPS_CAPABILITY_SCHEDULING = 0x0000001;
- private static final int GPS_CAPABILITY_MSB = 0x0000002;
- private static final int GPS_CAPABILITY_MSA = 0x0000004;
- private static final int GPS_CAPABILITY_SINGLE_SHOT = 0x0000008;
- private static final int GPS_CAPABILITY_ON_DEMAND_TIME = 0x0000010;
- public static final int GPS_CAPABILITY_GEOFENCING = 0x0000020;
- public static final int GPS_CAPABILITY_MEASUREMENTS = 0x0000040;
- public static final int GPS_CAPABILITY_NAV_MESSAGES = 0x0000080;
- public static final int GPS_CAPABILITY_LOW_POWER_MODE = 0x0000100;
- public static final int GPS_CAPABILITY_SATELLITE_BLOCKLIST = 0x0000200;
- public static final int GPS_CAPABILITY_MEASUREMENT_CORRECTIONS = 0x0000400;
- public static final int GPS_CAPABILITY_ANTENNA_INFO = 0x0000800;
+ ProviderProperties.POWER_USAGE_HIGH,
+ ProviderProperties.ACCURACY_FINE);
// The AGPS SUPL mode
private static final int AGPS_SUPL_MODE_MSA = 0x02;
private static final int AGPS_SUPL_MODE_MSB = 0x01;
+ // handler messages
private static final int INJECT_NTP_TIME = 5;
- // PSDS stands for Predicted Satellite Data Service
private static final int DOWNLOAD_PSDS_DATA = 6;
private static final int REQUEST_LOCATION = 16;
private static final int REPORT_LOCATION = 17; // HAL reports location
private static final int REPORT_SV_STATUS = 18; // HAL reports SV status
- // Request setid
- private static final int AGPS_RIL_REQUEST_SETID_IMSI = 1;
- private static final int AGPS_RIL_REQUEST_SETID_MSISDN = 2;
-
- // ref. location info
- private static final int AGPS_REF_LOCATION_TYPE_GSM_CELLID = 1;
- private static final int AGPS_REF_LOCATION_TYPE_UMTS_CELLID = 2;
-
- // set id info
- private static final int AGPS_SETID_TYPE_NONE = 0;
- private static final int AGPS_SETID_TYPE_IMSI = 1;
- private static final int AGPS_SETID_TYPE_MSISDN = 2;
-
- private static final int GPS_GEOFENCE_UNAVAILABLE = 1 << 0L;
- private static final int GPS_GEOFENCE_AVAILABLE = 1 << 1L;
-
- // GPS Geofence errors. Should match GeofenceStatus enum in IGnssGeofenceCallback.hal.
- private static final int GPS_GEOFENCE_OPERATION_SUCCESS = 0;
- private static final int GPS_GEOFENCE_ERROR_TOO_MANY_GEOFENCES = 100;
- private static final int GPS_GEOFENCE_ERROR_ID_EXISTS = -101;
- private static final int GPS_GEOFENCE_ERROR_ID_UNKNOWN = -102;
- private static final int GPS_GEOFENCE_ERROR_INVALID_TRANSITION = -103;
- private static final int GPS_GEOFENCE_ERROR_GENERIC = -149;
-
// TCP/IP constants.
// Valid TCP/UDP port range is (0, 65535].
private static final int TCP_MIN_PORT = 0;
@@ -290,19 +224,13 @@
private static final long LOCATION_OFF_DELAY_THRESHOLD_WARN_MILLIS = 2 * 1000;
private static final long LOCATION_OFF_DELAY_THRESHOLD_ERROR_MILLIS = 15 * 1000;
- private static final String DOWNLOAD_EXTRA_WAKELOCK_KEY = "GnssLocationProviderPsdsDownload";
-
- // Set lower than the current ITAR limit of 600m/s to allow this to trigger even if GPS HAL
- // stops output right at 600m/s, depriving this of the information of a device that reaches
- // greater than 600m/s, and higher than the speed of sound to avoid impacting most use cases.
- private static final float ITAR_SPEED_LIMIT_METERS_PER_SECOND = 400.0F;
-
-
private final Object mLock = new Object();
private final Context mContext;
private final Handler mHandler;
+ private final GnssNative mGnssNative;
+
@GuardedBy("mLock")
private final ExponentialBackOff mPsdsBackOff = new ExponentialBackOff(RETRY_INTERVAL,
MAX_RETRY_INTERVAL);
@@ -315,7 +243,6 @@
private boolean mBatchingEnabled;
private boolean mShutdown;
- private boolean mNavigating;
private boolean mStarted;
private boolean mBatchingStarted;
private long mStartedChangedElapsedRealtime;
@@ -335,9 +262,6 @@
private final WorkSource mClientSource = new WorkSource();
- // capabilities reported through the top level IGnssCallback.hal
- private volatile int mTopHalCapabilities;
-
// true if PSDS is supported
private boolean mSupportsPsds;
@GuardedBy("mLock")
@@ -358,15 +282,7 @@
private boolean mSuplEsEnabled = false;
private final LocationExtras mLocationExtras = new LocationExtras();
- private final GnssStatusProvider mGnssStatusListenerHelper;
- private final GnssMeasurementsProvider mGnssMeasurementsProvider;
- private final GnssMeasurementCorrectionsProvider mGnssMeasurementCorrectionsProvider;
- private final GnssAntennaInfoProvider mGnssAntennaInfoProvider;
- private final GnssNavigationMessageProvider mGnssNavigationMessageProvider;
- private final GnssPowerIndicationProvider mGnssPowerIndicationProvider;
private final NtpTimeHelper mNtpTimeHelper;
- private final GnssGeofenceProvider mGnssGeofenceProvider;
- private final GnssCapabilitiesProvider mGnssCapabilitiesProvider;
private final GnssSatelliteBlocklistHelper mGnssSatelliteBlocklistHelper;
// Available only on GNSS HAL 2.0 implementations and later.
@@ -385,44 +301,12 @@
private final AppOpsManager mAppOps;
private final IBatteryStats mBatteryStats;
- private GeofenceHardwareImpl mGeofenceHardwareImpl;
-
- // Volatile for simple inter-thread sync on these values.
- private volatile int mHardwareYear = 0;
- private volatile String mHardwareModelName;
-
- private volatile boolean mItarSpeedLimitExceeded = false;
-
@GuardedBy("mLock")
private final ArrayList<Runnable> mFlushListeners = new ArrayList<>(0);
// GNSS Metrics
private final GnssMetrics mGnssMetrics;
- public GnssStatusProvider getGnssStatusProvider() {
- return mGnssStatusListenerHelper;
- }
-
- public IGpsGeofenceHardware getGpsGeofenceProxy() {
- return mGnssGeofenceProvider;
- }
-
- public GnssMeasurementsProvider getGnssMeasurementsProvider() {
- return mGnssMeasurementsProvider;
- }
-
- public GnssMeasurementCorrectionsProvider getGnssMeasurementCorrectionsProvider() {
- return mGnssMeasurementCorrectionsProvider;
- }
-
- public GnssAntennaInfoProvider getGnssAntennaInfoProvider() {
- return mGnssAntennaInfoProvider;
- }
-
- public GnssNavigationMessageProvider getGnssNavigationMessageProvider() {
- return mGnssNavigationMessageProvider;
- }
-
/**
* Implements {@link GnssSatelliteBlocklistCallback#onUpdateSatelliteBlocklist}.
*/
@@ -486,20 +370,23 @@
}
}
- public GnssLocationProvider(Context context, Injector injector) {
- super(FgThread.getExecutor(), CallerIdentity.fromContext(context));
+ public GnssLocationProvider(Context context, Injector injector, GnssNative gnssNative,
+ GnssMetrics gnssMetrics) {
+ super(FgThread.getExecutor(), CallerIdentity.fromContext(context), PROPERTIES);
mContext = context;
+ mGnssNative = gnssNative;
+ mGnssMetrics = gnssMetrics;
// Create a wake lock
PowerManager powerManager = Objects.requireNonNull(
mContext.getSystemService(PowerManager.class));
- mWakeLock = powerManager.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, TAG);
+ mWakeLock = powerManager.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "*location*:" + TAG);
mWakeLock.setReferenceCounted(true);
// Create a separate wake lock for psds downloader as it may be released due to timeout.
mDownloadPsdsWakeLock = powerManager.newWakeLock(
- PowerManager.PARTIAL_WAKE_LOCK, DOWNLOAD_EXTRA_WAKELOCK_KEY);
+ PowerManager.PARTIAL_WAKE_LOCK, "*location*:PsdsDownload");
mDownloadPsdsWakeLock.setReferenceCounted(true);
mAlarmManager = (AlarmManager) mContext.getSystemService(Context.ALARM_SERVICE);
@@ -519,8 +406,7 @@
// relative long time, so the ctor() is kept to create objects needed by this instance,
// while IO initialization and registration is delegated to our internal handler
// this approach is just fine because events are posted to our handler anyway
- mGnssConfiguration = new GnssConfiguration(mContext);
- mGnssCapabilitiesProvider = new GnssCapabilitiesProvider();
+ mGnssConfiguration = mGnssNative.getConfiguration();
// Create a GPS net-initiated handler (also needed by handleInitialize)
mNIHandler = new GpsNetInitiatedHandler(context,
mNetInitiatedListener,
@@ -530,22 +416,21 @@
mNetworkConnectivityHandler = new GnssNetworkConnectivityHandler(context,
GnssLocationProvider.this::onNetworkAvailable, mHandler.getLooper(), mNIHandler);
- mGnssStatusListenerHelper = new GnssStatusProvider(injector);
- mGnssMeasurementsProvider = new GnssMeasurementsProvider(injector);
- mGnssMeasurementCorrectionsProvider = new GnssMeasurementCorrectionsProvider(mHandler);
- mGnssAntennaInfoProvider = new GnssAntennaInfoProvider(injector);
- mGnssNavigationMessageProvider = new GnssNavigationMessageProvider(injector);
- mGnssPowerIndicationProvider = new GnssPowerIndicationProvider();
-
- mGnssMetrics = new GnssMetrics(mContext, mBatteryStats);
mNtpTimeHelper = new NtpTimeHelper(mContext, mHandler.getLooper(), this);
mGnssSatelliteBlocklistHelper =
new GnssSatelliteBlocklistHelper(mContext,
mHandler.getLooper(), this);
- mGnssGeofenceProvider = new GnssGeofenceProvider();
- setProperties(PROPERTIES);
setAllowed(true);
+
+ mGnssNative.addBaseCallbacks(this);
+ mGnssNative.addLocationCallbacks(this);
+ mGnssNative.addSvStatusCallbacks(this);
+ mGnssNative.setAGpsCallbacks(this);
+ mGnssNative.setPsdsCallbacks(this);
+ mGnssNative.setNotificationCallbacks(this);
+ mGnssNative.setLocationRequestCallbacks(this);
+ mGnssNative.setTimeCallbacks(this);
}
/** Called when system is ready. */
@@ -575,12 +460,7 @@
}
private void handleInitialize() {
- // it *appears* that native_init() needs to be called at least once before invoking any
- // other gnss methods, so we cycle once on initialization.
- native_init();
- native_cleanup();
-
- if (native_is_gnss_visibility_control_supported()) {
+ if (mGnssNative.isGnssVisibilityControlSupported()) {
mGnssVisibilityControl = new GnssVisibilityControl(mContext, mHandler.getLooper(),
mNIHandler);
}
@@ -635,7 +515,7 @@
*/
@Override
public void injectTime(long time, long timeReference, int uncertainty) {
- native_inject_time(time, timeReference, uncertainty);
+ mGnssNative.injectTime(time, timeReference, uncertainty);
}
/**
@@ -647,7 +527,7 @@
if (mSupportsPsds) {
synchronized (mLock) {
for (int psdsType : mPendingDownloadPsdsTypes) {
- downloadPsdsData(psdsType);
+ sendMessage(DOWNLOAD_PSDS_DATA, psdsType, null);
}
mPendingDownloadPsdsTypes.clear();
}
@@ -724,38 +604,7 @@
return;
}
- int gnssLocationFlags = LOCATION_HAS_LAT_LONG
- | (location.hasAltitude() ? LOCATION_HAS_ALTITUDE : 0)
- | (location.hasSpeed() ? LOCATION_HAS_SPEED : 0)
- | (location.hasBearing() ? LOCATION_HAS_BEARING : 0)
- | (location.hasAccuracy() ? LOCATION_HAS_HORIZONTAL_ACCURACY : 0)
- | (location.hasVerticalAccuracy() ? LOCATION_HAS_VERTICAL_ACCURACY : 0)
- | (location.hasSpeedAccuracy() ? LOCATION_HAS_SPEED_ACCURACY : 0)
- | (location.hasBearingAccuracy() ? LOCATION_HAS_BEARING_ACCURACY : 0);
-
- double latitudeDegrees = location.getLatitude();
- double longitudeDegrees = location.getLongitude();
- double altitudeMeters = location.getAltitude();
- float speedMetersPerSec = location.getSpeed();
- float bearingDegrees = location.getBearing();
- float horizontalAccuracyMeters = location.getAccuracy();
- float verticalAccuracyMeters = location.getVerticalAccuracyMeters();
- float speedAccuracyMetersPerSecond = location.getSpeedAccuracyMetersPerSecond();
- float bearingAccuracyDegrees = location.getBearingAccuracyDegrees();
- long timestamp = location.getTime();
-
- int elapsedRealtimeFlags = ELAPSED_REALTIME_HAS_TIMESTAMP_NS
- | (location.hasElapsedRealtimeUncertaintyNanos()
- ? ELAPSED_REALTIME_HAS_TIME_UNCERTAINTY_NS : 0);
- long elapsedRealtimeNanos = location.getElapsedRealtimeNanos();
- double elapsedRealtimeUncertaintyNanos = location.getElapsedRealtimeUncertaintyNanos();
-
- native_inject_best_location(
- gnssLocationFlags, latitudeDegrees, longitudeDegrees,
- altitudeMeters, speedMetersPerSec, bearingDegrees,
- horizontalAccuracyMeters, verticalAccuracyMeters,
- speedAccuracyMetersPerSecond, bearingAccuracyDegrees, timestamp,
- elapsedRealtimeFlags, elapsedRealtimeNanos, elapsedRealtimeUncertaintyNanos);
+ mGnssNative.injectBestLocation(location);
}
/** Returns true if the location request is too frequent. */
@@ -789,7 +638,7 @@
if (data != null) {
mHandler.post(() -> {
if (DEBUG) Log.d(TAG, "calling native_inject_psds_data");
- native_inject_psds_data(data, data.length, psdsType);
+ mGnssNative.injectPsdsData(data, data.length, psdsType);
synchronized (mLock) {
mPsdsBackOff.reset();
}
@@ -824,9 +673,8 @@
}
private void injectLocation(Location location) {
- if (location.hasAccuracy() && !location.isFromMockProvider()) {
- native_inject_location(location.getLatitude(), location.getLongitude(),
- location.getAccuracy());
+ if (!location.isFromMockProvider()) {
+ mGnssNative.injectLocation(location);
}
}
@@ -836,7 +684,7 @@
if (mSuplServerHost != null
&& mSuplServerPort > TCP_MIN_PORT
&& mSuplServerPort <= TCP_MAX_PORT) {
- native_set_agps_server(GnssNetworkConnectivityHandler.AGPS_TYPE_SUPL,
+ mGnssNative.setAgpsServer(GnssNetworkConnectivityHandler.AGPS_TYPE_SUPL,
mSuplServerHost, mSuplServerPort);
}
}
@@ -852,16 +700,16 @@
if (agpsEnabled) {
int suplMode = mGnssConfiguration.getSuplMode(0);
if (suplMode == 0) {
- return GPS_POSITION_MODE_STANDALONE;
+ return GNSS_POSITION_MODE_STANDALONE;
}
// MS-Based is the preferred mode for Assisted-GPS position computation, so we favor
// such mode when it is available
- if (hasCapability(GPS_CAPABILITY_MSB) && (suplMode & AGPS_SUPL_MODE_MSB) != 0) {
- return GPS_POSITION_MODE_MS_BASED;
+ if (mGnssNative.getCapabilities().hasMsb() && (suplMode & AGPS_SUPL_MODE_MSB) != 0) {
+ return GNSS_POSITION_MODE_MS_BASED;
}
}
- return GPS_POSITION_MODE_STANDALONE;
+ return GNSS_POSITION_MODE_STANDALONE;
}
private void setGpsEnabled(boolean enabled) {
@@ -873,23 +721,23 @@
private void handleEnable() {
if (DEBUG) Log.d(TAG, "handleEnable");
- boolean inited = native_init();
+ boolean inited = mGnssNative.init();
if (inited) {
setGpsEnabled(true);
- mSupportsPsds = native_supports_psds();
+ mSupportsPsds = mGnssNative.isPsdsSupported();
// TODO: remove the following native calls if we can make sure they are redundant.
if (mSuplServerHost != null) {
- native_set_agps_server(GnssNetworkConnectivityHandler.AGPS_TYPE_SUPL,
+ mGnssNative.setAgpsServer(GnssNetworkConnectivityHandler.AGPS_TYPE_SUPL,
mSuplServerHost, mSuplServerPort);
}
if (mC2KServerHost != null) {
- native_set_agps_server(GnssNetworkConnectivityHandler.AGPS_TYPE_C2K,
+ mGnssNative.setAgpsServer(GnssNetworkConnectivityHandler.AGPS_TYPE_C2K,
mC2KServerHost, mC2KServerPort);
}
- mBatchingEnabled = native_init_batching() && native_get_batch_size() > 1;
+ mBatchingEnabled = mGnssNative.initBatching() && mGnssNative.getBatchSize() > 1;
if (mGnssVisibilityControl != null) {
mGnssVisibilityControl.onGpsEnabledChanged(/* isEnabled= */ true);
}
@@ -911,8 +759,8 @@
mGnssVisibilityControl.onGpsEnabledChanged(/* isEnabled= */ false);
}
// do this before releasing wakelock
- native_cleanup_batching();
- native_cleanup();
+ mGnssNative.cleanupBatching();
+ mGnssNative.cleanup();
}
private void updateEnabled() {
@@ -951,7 +799,7 @@
* minimum size guaranteed to be available for batching operations.
*/
public int getBatchSize() {
- return native_get_batch_size();
+ return mGnssNative.getBatchSize();
}
@Override
@@ -965,7 +813,7 @@
if (!added) {
listener.run();
} else {
- native_flush_batch();
+ mGnssNative.flushBatch();
}
}
@@ -1009,9 +857,9 @@
} else {
stopBatching();
- if (mStarted && hasCapability(GPS_CAPABILITY_SCHEDULING)) {
+ if (mStarted && mGnssNative.getCapabilities().hasScheduling()) {
// change period and/or lowPowerMode
- if (!setPositionMode(mPositionMode, GPS_POSITION_RECURRENCE_PERIODIC,
+ if (!setPositionMode(mPositionMode, GNSS_POSITION_RECURRENCE_PERIODIC,
mFixInterval, mProviderRequest.isLowPower())) {
Log.e(TAG, "set_position_mode failed in updateRequirements");
}
@@ -1045,8 +893,8 @@
return true;
}
- boolean result = native_set_position_mode(mode, recurrence, minInterval,
- 0, 0, lowPowerMode);
+ boolean result = mGnssNative.setPositionMode(mode, recurrence, minInterval, 0, 0,
+ lowPowerMode);
if (result) {
mLastPositionMode = positionMode;
} else {
@@ -1125,11 +973,11 @@
requestUtcTime();
} else if ("force_psds_injection".equals(command)) {
if (mSupportsPsds) {
- downloadPsdsData(/* psdsType= */
- GnssPsdsDownloader.LONG_TERM_PSDS_SERVER_INDEX);
+ sendMessage(DOWNLOAD_PSDS_DATA, GnssPsdsDownloader.LONG_TERM_PSDS_SERVER_INDEX,
+ null);
}
} else if ("request_power_stats".equals(command)) {
- GnssPowerIndicationProvider.requestPowerStats();
+ mGnssNative.requestPowerStats();
} else {
Log.w(TAG, "sendExtraCommand: unknown command " + command);
}
@@ -1139,26 +987,26 @@
int flags;
if (extras == null) {
- flags = GPS_DELETE_ALL;
+ flags = GNSS_AIDING_TYPE_ALL;
} else {
flags = 0;
- if (extras.getBoolean("ephemeris")) flags |= GPS_DELETE_EPHEMERIS;
- if (extras.getBoolean("almanac")) flags |= GPS_DELETE_ALMANAC;
- if (extras.getBoolean("position")) flags |= GPS_DELETE_POSITION;
- if (extras.getBoolean("time")) flags |= GPS_DELETE_TIME;
- if (extras.getBoolean("iono")) flags |= GPS_DELETE_IONO;
- if (extras.getBoolean("utc")) flags |= GPS_DELETE_UTC;
- if (extras.getBoolean("health")) flags |= GPS_DELETE_HEALTH;
- if (extras.getBoolean("svdir")) flags |= GPS_DELETE_SVDIR;
- if (extras.getBoolean("svsteer")) flags |= GPS_DELETE_SVSTEER;
- if (extras.getBoolean("sadata")) flags |= GPS_DELETE_SADATA;
- if (extras.getBoolean("rti")) flags |= GPS_DELETE_RTI;
- if (extras.getBoolean("celldb-info")) flags |= GPS_DELETE_CELLDB_INFO;
- if (extras.getBoolean("all")) flags |= GPS_DELETE_ALL;
+ if (extras.getBoolean("ephemeris")) flags |= GNSS_AIDING_TYPE_EPHEMERIS;
+ if (extras.getBoolean("almanac")) flags |= GNSS_AIDING_TYPE_ALMANAC;
+ if (extras.getBoolean("position")) flags |= GNSS_AIDING_TYPE_POSITION;
+ if (extras.getBoolean("time")) flags |= GNSS_AIDING_TYPE_TIME;
+ if (extras.getBoolean("iono")) flags |= GNSS_AIDING_TYPE_IONO;
+ if (extras.getBoolean("utc")) flags |= GNSS_AIDING_TYPE_UTC;
+ if (extras.getBoolean("health")) flags |= GNSS_AIDING_TYPE_HEALTH;
+ if (extras.getBoolean("svdir")) flags |= GNSS_AIDING_TYPE_SVDIR;
+ if (extras.getBoolean("svsteer")) flags |= GNSS_AIDING_TYPE_SVSTEER;
+ if (extras.getBoolean("sadata")) flags |= GNSS_AIDING_TYPE_SADATA;
+ if (extras.getBoolean("rti")) flags |= GNSS_AIDING_TYPE_RTI;
+ if (extras.getBoolean("celldb-info")) flags |= GNSS_AIDING_TYPE_CELLDB_INFO;
+ if (extras.getBoolean("all")) flags |= GNSS_AIDING_TYPE_ALL;
}
if (flags != 0) {
- native_delete_aiding_data(flags);
+ mGnssNative.deleteAidingData(flags);
}
}
@@ -1168,13 +1016,7 @@
mTimeToFirstFix = 0;
mLastFixTime = 0;
setStarted(true);
- mPositionMode = GPS_POSITION_MODE_STANDALONE;
- // Notify about suppressed output, if speed limit was previously exceeded.
- // Elsewhere, we check again with every speed output reported.
- if (mItarSpeedLimitExceeded) {
- Log.i(TAG, "startNavigating with ITAR limit in place. Output limited "
- + "until slow enough speed reported.");
- }
+ mPositionMode = GNSS_POSITION_MODE_STANDALONE;
boolean agpsEnabled =
(Settings.Global.getInt(mContext.getContentResolver(),
@@ -1185,13 +1027,13 @@
String mode;
switch (mPositionMode) {
- case GPS_POSITION_MODE_STANDALONE:
+ case GNSS_POSITION_MODE_STANDALONE:
mode = "standalone";
break;
- case GPS_POSITION_MODE_MS_ASSISTED:
+ case GNSS_POSITION_MODE_MS_ASSISTED:
mode = "MS_ASSISTED";
break;
- case GPS_POSITION_MODE_MS_BASED:
+ case GNSS_POSITION_MODE_MS_BASED:
mode = "MS_BASED";
break;
default:
@@ -1201,14 +1043,14 @@
Log.d(TAG, "setting position_mode to " + mode);
}
- int interval = (hasCapability(GPS_CAPABILITY_SCHEDULING) ? mFixInterval : 1000);
- if (!setPositionMode(mPositionMode, GPS_POSITION_RECURRENCE_PERIODIC,
+ int interval = mGnssNative.getCapabilities().hasScheduling() ? mFixInterval : 1000;
+ if (!setPositionMode(mPositionMode, GNSS_POSITION_RECURRENCE_PERIODIC,
interval, mProviderRequest.isLowPower())) {
setStarted(false);
Log.e(TAG, "set_position_mode failed in startNavigating()");
return;
}
- if (!native_start()) {
+ if (!mGnssNative.start()) {
setStarted(false);
Log.e(TAG, "native_start failed in startNavigating()");
return;
@@ -1217,7 +1059,7 @@
// reset SV count to zero
mLocationExtras.reset();
mFixRequestTime = SystemClock.elapsedRealtime();
- if (!hasCapability(GPS_CAPABILITY_SCHEDULING)) {
+ if (!mGnssNative.getCapabilities().hasScheduling()) {
// set timer to give up if we do not receive a fix within NO_FIX_TIMEOUT
// and our fix interval is not short
if (mFixInterval >= NO_FIX_TIMEOUT) {
@@ -1233,7 +1075,7 @@
if (DEBUG) Log.d(TAG, "stopNavigating");
if (mStarted) {
setStarted(false);
- native_stop();
+ mGnssNative.stop();
mLastFixTime = 0;
// native_stop() may reset the position mode in hardware.
mLastPositionMode = null;
@@ -1249,7 +1091,7 @@
if (DEBUG) {
Log.d(TAG, "startBatching " + mFixInterval);
}
- if (native_start_batch(MILLISECONDS.toNanos(mFixInterval), true)) {
+ if (mGnssNative.startBatch(MILLISECONDS.toNanos(mFixInterval), true)) {
mBatchingStarted = true;
} else {
Log.e(TAG, "native_start_batch failed in startBatching()");
@@ -1259,7 +1101,7 @@
private void stopBatching() {
if (DEBUG) Log.d(TAG, "stopBatching");
if (mBatchingStarted) {
- native_stop_batch();
+ mGnssNative.stopBatch();
mBatchingStarted = false;
}
}
@@ -1279,28 +1121,7 @@
mWakeupListener, mHandler);
}
- private boolean hasCapability(int capability) {
- return (mTopHalCapabilities & capability) != 0;
- }
-
- void reportLocation(boolean hasLatLong, Location location) {
- sendMessage(REPORT_LOCATION, hasLatLong ? 1 : 0, location);
- }
-
private void handleReportLocation(boolean hasLatLong, Location location) {
- if (location.hasSpeed()) {
- mItarSpeedLimitExceeded = location.getSpeed() > ITAR_SPEED_LIMIT_METERS_PER_SECOND;
- }
-
- if (mItarSpeedLimitExceeded) {
- Log.i(TAG, "Hal reported a speed in excess of ITAR limit."
- + " GPS/GNSS Navigation output blocked.");
- if (mStarted) {
- mGnssMetrics.logReceivedLocationStatus(false);
- }
- return; // No output of location allowed
- }
-
if (VERBOSE) Log.v(TAG, "reportLocation " + location.toString());
location.setExtras(mLocationExtras.getBundle());
@@ -1343,9 +1164,6 @@
if (mStarted) {
mGnssMetrics.logTimeToFirstFixMilliSecs(mTimeToFirstFix);
}
-
- // notify status listeners
- mGnssStatusListenerHelper.onFirstFix(mTimeToFirstFix);
}
if (mStarted) {
@@ -1353,51 +1171,19 @@
// 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) {
+ if (!mGnssNative.getCapabilities().hasScheduling() && mFixInterval < NO_FIX_TIMEOUT) {
mAlarmManager.cancel(mTimeoutListener);
}
}
- if (!hasCapability(GPS_CAPABILITY_SCHEDULING) && mStarted
+ if (!mGnssNative.getCapabilities().hasScheduling() && mStarted
&& mFixInterval > GPS_POLLING_THRESHOLD_INTERVAL) {
if (DEBUG) Log.d(TAG, "got fix, hibernating");
hibernate();
}
}
- void reportStatus(int status) {
- if (DEBUG) Log.v(TAG, "reportStatus status: " + status);
-
- boolean wasNavigating = mNavigating;
- switch (status) {
- case GPS_STATUS_SESSION_BEGIN:
- mNavigating = true;
- break;
- case GPS_STATUS_ENGINE_ON:
- break;
- case GPS_STATUS_SESSION_END:
- // fall through
- case GPS_STATUS_ENGINE_OFF:
- mNavigating = false;
- break;
- }
-
- if (wasNavigating != mNavigating) {
- mGnssStatusListenerHelper.onStatusChanged(mNavigating);
- }
- }
-
- void reportSvStatus(int svCount, int[] svidWithFlags, float[] cn0DbHzs,
- float[] elevations, float[] azimuths, float[] carrierFrequencies,
- float[] basebandCn0DbHzs) {
- sendMessage(REPORT_SV_STATUS, 0,
- GnssStatus.wrap(svCount, svidWithFlags, cn0DbHzs, elevations, azimuths,
- carrierFrequencies, basebandCn0DbHzs));
- }
-
private void handleReportSvStatus(GnssStatus gnssStatus) {
- mGnssStatusListenerHelper.onSvStatusChanged(gnssStatus);
-
// Log CN0 as part of GNSS metrics
mGnssMetrics.logCn0(gnssStatus);
@@ -1427,289 +1213,12 @@
mGnssMetrics.logSvStatus(gnssStatus);
}
- void reportAGpsStatus(int agpsType, int agpsStatus, byte[] suplIpAddr) {
- mNetworkConnectivityHandler.onReportAGpsStatus(agpsType, agpsStatus, suplIpAddr);
- }
-
- void reportNmea(long timestamp) {
- if (!mItarSpeedLimitExceeded) {
- int length = native_read_nmea(mNmeaBuffer, mNmeaBuffer.length);
- String nmea = new String(mNmeaBuffer, 0 /* offset */, length);
- mGnssStatusListenerHelper.onNmeaReceived(timestamp, nmea);
- }
- }
-
- void reportMeasurementData(GnssMeasurementsEvent event) {
- if (!mItarSpeedLimitExceeded) {
- // send to handler to allow native to return quickly
- mHandler.post(() -> mGnssMeasurementsProvider.onMeasurementsAvailable(event));
- }
- }
-
- void reportAntennaInfo(List<GnssAntennaInfo> antennaInfos) {
- mHandler.post(() -> mGnssAntennaInfoProvider.onGnssAntennaInfoAvailable(antennaInfos));
- }
-
- void reportNavigationMessage(GnssNavigationMessage event) {
- if (!mItarSpeedLimitExceeded) {
- // send to handler to allow native to return quickly
- mHandler.post(() -> mGnssNavigationMessageProvider.onNavigationMessageAvailable(event));
- }
- }
-
- void reportGnssPowerStats(GnssPowerStats powerStats) {
- mHandler.post(() -> mGnssPowerIndicationProvider.onGnssPowerStatsAvailable(powerStats));
- }
-
- void setTopHalCapabilities(int topHalCapabilities) {
- mHandler.post(() -> {
- mTopHalCapabilities = topHalCapabilities;
-
- if (hasCapability(GPS_CAPABILITY_ON_DEMAND_TIME)) {
- mNtpTimeHelper.enablePeriodicTimeInjection();
- requestUtcTime();
- }
-
- restartRequests();
-
- mGnssCapabilitiesProvider.setTopHalCapabilities(mTopHalCapabilities);
- });
- }
-
- void setSubHalMeasurementCorrectionsCapabilities(int subHalCapabilities) {
- mHandler.post(() -> {
- if (!mGnssMeasurementCorrectionsProvider.onCapabilitiesUpdated(subHalCapabilities)) {
- return;
- }
-
- mGnssCapabilitiesProvider.setSubHalMeasurementCorrectionsCapabilities(
- subHalCapabilities);
- });
- }
-
- /**
- * Sets the capabilities bits for IGnssPowerIndication HAL.
- *
- * These capabilities are defined in IGnssPowerIndicationCallback.aidl.
- */
- void setSubHalPowerIndicationCapabilities(int subHalCapabilities) {
- mHandler.post(() -> mGnssPowerIndicationProvider.onCapabilitiesUpdated(subHalCapabilities));
- }
-
- private void restartRequests() {
- Log.i(TAG, "restartRequests");
-
- restartLocationRequest();
- mGnssGeofenceProvider.resumeIfStarted();
- }
-
private void restartLocationRequest() {
if (DEBUG) Log.d(TAG, "restartLocationRequest");
setStarted(false);
updateRequirements();
}
- 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;
- }
-
- 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;
- }
-
- void reportGnssServiceRestarted() {
- if (DEBUG) Log.d(TAG, "reportGnssServiceDied");
-
- // it *appears* that native_init() needs to be called at least once before invoking any
- // other gnss methods, so we cycle once on initialization.
- native_init();
- native_cleanup();
-
- // resend configuration into the restarted HAL service.
- reloadGpsProperties();
- if (isGpsEnabled()) {
- setGpsEnabled(false);
- updateEnabled();
- }
- }
-
- /**
- * Interface for GnssSystemInfo methods.
- */
- public interface GnssSystemInfoProvider {
- /**
- * Returns the year of underlying GPS hardware.
- */
- int getGnssYearOfHardware();
-
- /**
- * Returns the model name of underlying GPS hardware.
- */
- String getGnssHardwareModelName();
- }
-
- /**
- * @hide
- */
- public GnssSystemInfoProvider getGnssSystemInfoProvider() {
- return new GnssSystemInfoProvider() {
- @Override
- public int getGnssYearOfHardware() {
- return mHardwareYear;
- }
-
- @Override
- public String getGnssHardwareModelName() {
- return mHardwareModelName;
- }
- };
- }
-
- /**
- * Interface for GnssMetrics methods.
- */
- public interface GnssMetricsProvider {
- /**
- * Returns GNSS metrics as proto string
- */
- String getGnssMetricsAsProtoString();
- }
-
- /**
- * @hide
- */
- public GnssMetricsProvider getGnssMetricsProvider() {
- return mGnssMetrics::dumpGnssMetricsAsProtoString;
- }
-
- /**
- * @hide
- */
- public GnssCapabilitiesProvider getGnssCapabilitiesProvider() {
- return mGnssCapabilitiesProvider;
- }
-
- void reportLocationBatch(Location[] locations) {
- if (DEBUG) {
- Log.d(TAG, "Location batch of size " + locations.length + " reported");
- }
-
- Runnable[] listeners;
- synchronized (mLock) {
- listeners = mFlushListeners.toArray(new Runnable[0]);
- mFlushListeners.clear();
- }
-
- if (locations.length > 0) {
- reportLocation(LocationResult.create(Arrays.asList(locations)).validate());
- }
-
- for (Runnable listener : listeners) {
- listener.run();
- }
- }
-
- void downloadPsdsData(int psdsType) {
- if (DEBUG) Log.d(TAG, "downloadPsdsData. psdsType: " + psdsType);
- sendMessage(DOWNLOAD_PSDS_DATA, psdsType, null);
- }
-
- /**
- * Converts the GPS HAL status to the internal Geofence Hardware status.
- */
- private static int getGeofenceStatus(int status) {
- switch (status) {
- case GPS_GEOFENCE_OPERATION_SUCCESS:
- return GeofenceHardware.GEOFENCE_SUCCESS;
- case GPS_GEOFENCE_ERROR_GENERIC:
- return GeofenceHardware.GEOFENCE_FAILURE;
- case GPS_GEOFENCE_ERROR_ID_EXISTS:
- return GeofenceHardware.GEOFENCE_ERROR_ID_EXISTS;
- case GPS_GEOFENCE_ERROR_INVALID_TRANSITION:
- return GeofenceHardware.GEOFENCE_ERROR_INVALID_TRANSITION;
- case GPS_GEOFENCE_ERROR_TOO_MANY_GEOFENCES:
- return GeofenceHardware.GEOFENCE_ERROR_TOO_MANY_GEOFENCES;
- case GPS_GEOFENCE_ERROR_ID_UNKNOWN:
- return GeofenceHardware.GEOFENCE_ERROR_ID_UNKNOWN;
- default:
- return -1;
- }
- }
-
- void reportGeofenceTransition(int geofenceId, Location location, int transition,
- long transitionTimestamp) {
- mHandler.post(() -> {
- if (mGeofenceHardwareImpl == null) {
- mGeofenceHardwareImpl = GeofenceHardwareImpl.getInstance(mContext);
- }
-
- mGeofenceHardwareImpl.reportGeofenceTransition(
- geofenceId,
- location,
- transition,
- transitionTimestamp,
- GeofenceHardware.MONITORING_TYPE_GPS_HARDWARE,
- FusedBatchOptions.SourceTechnologies.GNSS);
- });
- }
-
- void reportGeofenceStatus(int status, Location location) {
- 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);
- });
- }
-
- void reportGeofenceAddStatus(int geofenceId, int status) {
- mHandler.post(() -> {
- if (mGeofenceHardwareImpl == null) {
- mGeofenceHardwareImpl = GeofenceHardwareImpl.getInstance(mContext);
- }
- mGeofenceHardwareImpl.reportGeofenceAddStatus(geofenceId, getGeofenceStatus(status));
- });
- }
-
- void reportGeofenceRemoveStatus(int geofenceId, int status) {
- mHandler.post(() -> {
- if (mGeofenceHardwareImpl == null) {
- mGeofenceHardwareImpl = GeofenceHardwareImpl.getInstance(mContext);
- }
- mGeofenceHardwareImpl.reportGeofenceRemoveStatus(geofenceId, getGeofenceStatus(status));
- });
- }
-
- void reportGeofencePauseStatus(int geofenceId, int status) {
- mHandler.post(() -> {
- if (mGeofenceHardwareImpl == null) {
- mGeofenceHardwareImpl = GeofenceHardwareImpl.getInstance(mContext);
- }
- mGeofenceHardwareImpl.reportGeofencePauseStatus(geofenceId, getGeofenceStatus(status));
- });
- }
-
- void reportGeofenceResumeStatus(int geofenceId, int status) {
- mHandler.post(() -> {
- if (mGeofenceHardwareImpl == null) {
- mGeofenceHardwareImpl = GeofenceHardwareImpl.getInstance(mContext);
- }
- mGeofenceHardwareImpl.reportGeofenceResumeStatus(geofenceId, getGeofenceStatus(status));
- });
- }
-
//=============================================================
// NI Client support
//=============================================================
@@ -1723,7 +1232,7 @@
Log.d(TAG, "sendNiResponse, notifId: " + notificationId
+ ", response: " + userResponse);
}
- native_send_ni_response(notificationId, userResponse);
+ mGnssNative.sendNiResponse(notificationId, userResponse);
FrameworkStatsLog.write(FrameworkStatsLog.GNSS_NI_EVENT_REPORTED,
FrameworkStatsLog.GNSS_NI_EVENT_REPORTED__EVENT_TYPE__NI_RESPONSE,
@@ -1751,7 +1260,7 @@
}
/** Reports a NI notification. */
- void reportNiNotification(int notificationId, int niType, int notifyFlags, int timeout,
+ private void reportNiNotification(int notificationId, int niType, int notifyFlags, int timeout,
int defaultResponse, String requestorId, String text, int requestorIdEncoding,
int textEncoding) {
Log.i(TAG, "reportNiNotification: entered");
@@ -1800,52 +1309,12 @@
/* userResponse= */ 0);
}
- /**
- * We should be careful about receiving null string from the TelephonyManager,
- * because sending null String to JNI function would cause a crash.
- */
- void requestSetID(int flags) {
- TelephonyManager phone = (TelephonyManager)
- mContext.getSystemService(Context.TELEPHONY_SERVICE);
- int type = AGPS_SETID_TYPE_NONE;
- String setId = null;
-
- int ddSubId = SubscriptionManager.getDefaultDataSubscriptionId();
- if (SubscriptionManager.isValidSubscriptionId(ddSubId)) {
- phone = phone.createForSubscriptionId(ddSubId);
- }
- if ((flags & AGPS_RIL_REQUEST_SETID_IMSI) == AGPS_RIL_REQUEST_SETID_IMSI) {
- setId = phone.getSubscriberId();
- if (setId != null) {
- // This means the framework has the SIM card.
- type = AGPS_SETID_TYPE_IMSI;
- }
- } else if ((flags & AGPS_RIL_REQUEST_SETID_MSISDN) == AGPS_RIL_REQUEST_SETID_MSISDN) {
- setId = phone.getLine1Number();
- if (setId != null) {
- // This means the framework has the SIM card.
- type = AGPS_SETID_TYPE_MSISDN;
- }
- }
-
- native_agps_set_id(type, (setId == null) ? "" : setId);
- }
-
- void requestLocation(boolean independentFromGnss, boolean isUserEmergency) {
- if (DEBUG) {
- Log.d(TAG, "requestLocation. independentFromGnss: " + independentFromGnss
- + ", isUserEmergency: "
- + isUserEmergency);
- }
- sendMessage(REQUEST_LOCATION, independentFromGnss ? 1 : 0, isUserEmergency);
- }
-
- void requestUtcTime() {
+ private void requestUtcTime() {
if (DEBUG) Log.d(TAG, "utcTimeRequest");
sendMessage(INJECT_NTP_TIME, 0, null);
}
- void requestRefLocation() {
+ private void requestRefLocation() {
TelephonyManager phone = (TelephonyManager)
mContext.getSystemService(Context.TELEPHONY_SERVICE);
final int phoneType = phone.getPhoneType();
@@ -1866,8 +1335,8 @@
} else {
type = AGPS_REF_LOCATION_TYPE_GSM_CELLID;
}
- native_agps_set_ref_location_cellid(type, mcc, mnc,
- gsm_cell.getLac(), gsm_cell.getCid());
+ mGnssNative.setAgpsReferenceLocationCellId(type, mcc, mnc, gsm_cell.getLac(),
+ gsm_cell.getCid());
} else {
Log.e(TAG, "Error getting cell location info.");
}
@@ -1876,21 +1345,6 @@
}
}
- // Implements method nfwNotifyCb() in IGnssVisibilityControlCallback.hal.
- void reportNfwNotification(String proxyAppPackageName, byte protocolStack,
- String otherProtocolStackName, byte requestor, String requestorId, byte responseType,
- boolean inEmergencyMode, boolean isCachedLocation) {
- if (mGnssVisibilityControl == null) {
- Log.e(TAG, "reportNfwNotification: mGnssVisibilityControl is not initialized.");
- return;
- }
-
- mGnssVisibilityControl.reportNfwNotification(proxyAppPackageName, protocolStack,
- otherProtocolStackName, requestor, requestorId, responseType, inEmergencyMode,
- isCachedLocation);
- }
-
- // Implements method isInEmergencySession() in IGnssVisibilityControlCallback.hal.
boolean isInEmergencySession() {
return mNIHandler.getInEmergency();
}
@@ -1988,97 +1442,143 @@
pw.println("mBatchingStarted=" + mBatchingStarted);
pw.println("mBatchSize=" + getBatchSize());
pw.println("mFixInterval=" + mFixInterval);
- mGnssPowerIndicationProvider.dump(fd, pw, args);
- pw.print("mTopHalCapabilities=0x" + Integer.toHexString(mTopHalCapabilities) + " ( ");
- if (hasCapability(GPS_CAPABILITY_SCHEDULING)) pw.print("SCHEDULING ");
- if (hasCapability(GPS_CAPABILITY_MSB)) pw.print("MSB ");
- if (hasCapability(GPS_CAPABILITY_MSA)) pw.print("MSA ");
- if (hasCapability(GPS_CAPABILITY_SINGLE_SHOT)) pw.print("SINGLE_SHOT ");
- if (hasCapability(GPS_CAPABILITY_ON_DEMAND_TIME)) pw.print("ON_DEMAND_TIME ");
- if (hasCapability(GPS_CAPABILITY_GEOFENCING)) pw.print("GEOFENCING ");
- if (hasCapability(GPS_CAPABILITY_MEASUREMENTS)) pw.print("MEASUREMENTS ");
- if (hasCapability(GPS_CAPABILITY_NAV_MESSAGES)) pw.print("NAV_MESSAGES ");
- if (hasCapability(GPS_CAPABILITY_LOW_POWER_MODE)) pw.print("LOW_POWER_MODE ");
- if (hasCapability(GPS_CAPABILITY_SATELLITE_BLOCKLIST)) pw.print("SATELLITE_BLOCKLIST ");
- if (hasCapability(GPS_CAPABILITY_MEASUREMENT_CORRECTIONS)) {
- pw.print("MEASUREMENT_CORRECTIONS ");
- }
- if (hasCapability(GPS_CAPABILITY_ANTENNA_INFO)) pw.print("ANTENNA_INFO ");
- pw.println(")");
- if (hasCapability(GPS_CAPABILITY_MEASUREMENT_CORRECTIONS)) {
- pw.println("SubHal=MEASUREMENT_CORRECTIONS["
- + mGnssMeasurementCorrectionsProvider.toStringCapabilities() + "]");
- }
pw.print(mGnssMetrics.dumpGnssMetricsAsText());
if (dumpAll) {
pw.println("native internal state: ");
- pw.println(" " + native_get_internal_state());
+ pw.println(" " + mGnssNative.getInternalState());
}
}
- // preallocated to avoid memory allocation in reportNmea()
- private final byte[] mNmeaBuffer = new byte[120];
+ @Override
+ public void onHalRestarted() {
+ reloadGpsProperties();
+ if (isGpsEnabled()) {
+ setGpsEnabled(false);
+ updateEnabled();
+ }
+ }
- private static native boolean native_is_gnss_visibility_control_supported();
+ @Override
+ public void onCapabilitiesChanged(GnssCapabilities oldCapabilities,
+ GnssCapabilities newCapabilities) {
+ mHandler.post(() -> {
+ if (mGnssNative.getCapabilities().hasOnDemandTime()) {
+ mNtpTimeHelper.enablePeriodicTimeInjection();
+ requestUtcTime();
+ }
- private native boolean native_init();
+ restartLocationRequest();
+ });
+ }
- private native void native_cleanup();
+ @Override
+ public void onReportLocation(boolean hasLatLong, Location location) {
+ sendMessage(REPORT_LOCATION, hasLatLong ? 1 : 0, location);
+ }
- private native boolean native_set_position_mode(int mode, int recurrence, int minInterval,
- int preferredAccuracy, int preferredTime, boolean lowPowerMode);
+ @Override
+ public void onReportLocations(Location[] locations) {
+ if (DEBUG) {
+ Log.d(TAG, "Location batch of size " + locations.length + " reported");
+ }
- private native boolean native_start();
+ Runnable[] listeners;
+ synchronized (mLock) {
+ listeners = mFlushListeners.toArray(new Runnable[0]);
+ mFlushListeners.clear();
+ }
- private native boolean native_stop();
+ if (locations.length > 0) {
+ reportLocation(LocationResult.create(Arrays.asList(locations)).validate());
+ }
- private native void native_delete_aiding_data(int flags);
+ for (Runnable listener : listeners) {
+ listener.run();
+ }
+ }
- private native int native_read_nmea(byte[] buffer, int bufferSize);
+ @Override
+ public void onReportSvStatus(GnssStatus gnssStatus) {
+ sendMessage(REPORT_SV_STATUS, 0, gnssStatus);
+ }
- private native void native_inject_best_location(
- int gnssLocationFlags, double latitudeDegrees, double longitudeDegrees,
- double altitudeMeters, float speedMetersPerSec, float bearingDegrees,
- float horizontalAccuracyMeters, float verticalAccuracyMeters,
- float speedAccuracyMetersPerSecond, float bearingAccuracyDegrees,
- long timestamp, int elapsedRealtimeFlags, long elapsedRealtimeNanos,
- double elapsedRealtimeUncertaintyNanos);
+ @Override
+ public void onReportAGpsStatus(int agpsType, int agpsStatus, byte[] suplIpAddr) {
+ mNetworkConnectivityHandler.onReportAGpsStatus(agpsType, agpsStatus, suplIpAddr);
+ }
- private native void native_inject_location(double latitude, double longitude, float accuracy);
+ @Override
+ public void onRequestPsdsDownload(int psdsType) {
+ sendMessage(DOWNLOAD_PSDS_DATA, psdsType, null);
+ }
- // PSDS Support
- private native void native_inject_time(long time, long timeReference, int uncertainty);
+ @Override
+ public void onReportNiNotification(int notificationId, int niType, int notifyFlags,
+ int timeout, int defaultResponse, String requestorId, String text,
+ int requestorIdEncoding, int textEncoding) {
+ reportNiNotification(notificationId, niType, notifyFlags, timeout,
+ defaultResponse, requestorId, text, requestorIdEncoding, textEncoding);
+ }
- private native boolean native_supports_psds();
+ @Override
+ public void onRequestSetID(@GnssNative.AGpsCallbacks.AgpsSetIdFlags int flags) {
+ TelephonyManager phone = (TelephonyManager)
+ mContext.getSystemService(Context.TELEPHONY_SERVICE);
+ int type = AGPS_SETID_TYPE_NONE;
+ String setId = null;
- private native void native_inject_psds_data(byte[] data, int length, int psdsType);
+ int ddSubId = SubscriptionManager.getDefaultDataSubscriptionId();
+ if (SubscriptionManager.isValidSubscriptionId(ddSubId)) {
+ phone = phone.createForSubscriptionId(ddSubId);
+ }
+ if ((flags & AGPS_REQUEST_SETID_IMSI) == AGPS_REQUEST_SETID_IMSI) {
+ setId = phone.getSubscriberId();
+ if (setId != null) {
+ // This means the framework has the SIM card.
+ type = AGPS_SETID_TYPE_IMSI;
+ }
+ } else if ((flags & AGPS_REQUEST_SETID_MSISDN) == AGPS_REQUEST_SETID_MSISDN) {
+ setId = phone.getLine1Number();
+ if (setId != null) {
+ // This means the framework has the SIM card.
+ type = AGPS_SETID_TYPE_MSISDN;
+ }
+ }
- // DEBUG Support
- private native String native_get_internal_state();
+ mGnssNative.setAgpsSetId(type, (setId == null) ? "" : setId);
+ }
- // AGPS Support
- private native void native_agps_ni_message(byte[] msg, int length);
+ @Override
+ public void onRequestLocation(boolean independentFromGnss, boolean isUserEmergency) {
+ if (DEBUG) {
+ Log.d(TAG, "requestLocation. independentFromGnss: " + independentFromGnss
+ + ", isUserEmergency: "
+ + isUserEmergency);
+ }
+ sendMessage(REQUEST_LOCATION, independentFromGnss ? 1 : 0, isUserEmergency);
+ }
- private native void native_set_agps_server(int type, String hostname, int port);
+ @Override
+ public void onRequestUtcTime() {
+ requestUtcTime();
+ }
- // Network-initiated (NI) Support
- private native void native_send_ni_response(int notificationId, int userResponse);
+ @Override
+ public void onRequestRefLocation() {
+ requestRefLocation();
+ }
- // AGPS ril support
- private native void native_agps_set_ref_location_cellid(int type, int mcc, int mnc,
- int lac, int cid);
+ @Override
+ public void onReportNfwNotification(String proxyAppPackageName, byte protocolStack,
+ String otherProtocolStackName, byte requestor, String requestorId,
+ byte responseType, boolean inEmergencyMode, boolean isCachedLocation) {
+ if (mGnssVisibilityControl == null) {
+ Log.e(TAG, "reportNfwNotification: mGnssVisibilityControl uninitialized.");
+ return;
+ }
- private native void native_agps_set_id(int type, String setid);
-
- private static native boolean native_init_batching();
-
- private static native void native_cleanup_batching();
-
- private static native int native_get_batch_size();
-
- private static native boolean native_start_batch(long periodNanos, boolean wakeOnFifoFull);
-
- private static native void native_flush_batch();
-
- private static native boolean native_stop_batch();
+ mGnssVisibilityControl.reportNfwNotification(proxyAppPackageName, protocolStack,
+ otherProtocolStackName, requestor, requestorId, responseType, inEmergencyMode,
+ isCachedLocation);
+ }
}
diff --git a/services/core/java/com/android/server/location/gnss/GnssManagerService.java b/services/core/java/com/android/server/location/gnss/GnssManagerService.java
index fa137aa..ff92444 100644
--- a/services/core/java/com/android/server/location/gnss/GnssManagerService.java
+++ b/services/core/java/com/android/server/location/gnss/GnssManagerService.java
@@ -19,99 +19,78 @@
import android.Manifest;
import android.annotation.Nullable;
import android.content.Context;
-import android.location.GnssAntennaInfo;
+import android.hardware.location.GeofenceHardware;
+import android.hardware.location.GeofenceHardwareImpl;
+import android.location.FusedBatchOptions;
+import android.location.GnssCapabilities;
import android.location.GnssMeasurementCorrections;
import android.location.GnssMeasurementRequest;
-import android.location.GnssMeasurementsEvent;
-import android.location.GnssNavigationMessage;
import android.location.IGnssAntennaInfoListener;
import android.location.IGnssMeasurementsListener;
import android.location.IGnssNavigationMessageListener;
+import android.location.IGnssNmeaListener;
import android.location.IGnssStatusListener;
import android.location.IGpsGeofenceHardware;
-import android.location.INetInitiatedListener;
import android.location.Location;
-import android.location.LocationManagerInternal;
import android.location.util.identity.CallerIdentity;
+import android.os.BatteryStats;
import android.os.RemoteException;
+import android.os.ServiceManager;
import android.util.IndentingPrintWriter;
import android.util.Log;
-import com.android.internal.annotations.VisibleForTesting;
-import com.android.internal.util.Preconditions;
-import com.android.server.LocalServices;
-import com.android.server.location.injector.AppOpsHelper;
+import com.android.internal.app.IBatteryStats;
+import com.android.server.FgThread;
+import com.android.server.location.gnss.hal.GnssNative;
import com.android.server.location.injector.Injector;
import java.io.FileDescriptor;
-import java.util.List;
/** Manages Gnss providers and related Gnss functions for LocationManagerService. */
-public class GnssManagerService implements GnssNative.Callbacks {
+public class GnssManagerService {
public static final String TAG = "GnssManager";
public static final boolean D = Log.isLoggable(TAG, Log.DEBUG);
private static final String ATTRIBUTION_ID = "GnssService";
- public static boolean isGnssSupported() {
- return GnssNative.isSupported();
- }
-
private final Context mContext;
- private final AppOpsHelper mAppOpsHelper;
- private final LocationManagerInternal mLocationManagerInternal;
+ private final GnssNative mGnssNative;
private final GnssLocationProvider mGnssLocationProvider;
private final GnssStatusProvider mGnssStatusProvider;
+ private final GnssNmeaProvider mGnssNmeaProvider;
private final GnssMeasurementsProvider mGnssMeasurementsProvider;
- private final GnssMeasurementCorrectionsProvider mGnssMeasurementCorrectionsProvider;
private final GnssAntennaInfoProvider mGnssAntennaInfoProvider;
private final GnssNavigationMessageProvider mGnssNavigationMessageProvider;
- private final GnssLocationProvider.GnssSystemInfoProvider mGnssSystemInfoProvider;
- private final GnssLocationProvider.GnssMetricsProvider mGnssMetricsProvider;
- private final GnssCapabilitiesProvider mGnssCapabilitiesProvider;
- private final INetInitiatedListener mNetInitiatedListener;
- private final IGpsGeofenceHardware mGpsGeofenceProxy;
+ private final IGpsGeofenceHardware mGnssGeofenceProxy;
- public GnssManagerService(Context context, Injector injector) {
- this(context, injector, null);
- }
+ private final GnssMetrics mGnssMetrics;
- @VisibleForTesting
- GnssManagerService(Context context, Injector injector,
- GnssLocationProvider gnssLocationProvider) {
- Preconditions.checkState(isGnssSupported());
-
- GnssNative.initialize();
-
+ public GnssManagerService(Context context, Injector injector, GnssNative gnssNative) {
mContext = context.createAttributionContext(ATTRIBUTION_ID);
- mAppOpsHelper = injector.getAppOpsHelper();
- mLocationManagerInternal = LocalServices.getService(LocationManagerInternal.class);
+ mGnssNative = gnssNative;
- if (gnssLocationProvider == null) {
- gnssLocationProvider = new GnssLocationProvider(mContext, injector);
- }
+ mGnssMetrics = new GnssMetrics(mContext, IBatteryStats.Stub.asInterface(
+ ServiceManager.getService(BatteryStats.SERVICE_NAME)));
- mGnssLocationProvider = gnssLocationProvider;
- mGnssStatusProvider = mGnssLocationProvider.getGnssStatusProvider();
- mGnssMeasurementsProvider = mGnssLocationProvider.getGnssMeasurementsProvider();
- mGnssAntennaInfoProvider = mGnssLocationProvider.getGnssAntennaInfoProvider();
- mGnssMeasurementCorrectionsProvider =
- mGnssLocationProvider.getGnssMeasurementCorrectionsProvider();
- mGnssNavigationMessageProvider = mGnssLocationProvider.getGnssNavigationMessageProvider();
- mGnssSystemInfoProvider = mGnssLocationProvider.getGnssSystemInfoProvider();
- mGnssMetricsProvider = mGnssLocationProvider.getGnssMetricsProvider();
- mGnssCapabilitiesProvider = mGnssLocationProvider.getGnssCapabilitiesProvider();
- mNetInitiatedListener = mGnssLocationProvider.getNetInitiatedListener();
- mGpsGeofenceProxy = mGnssLocationProvider.getGpsGeofenceProxy();
+ mGnssLocationProvider = new GnssLocationProvider(mContext, injector, mGnssNative,
+ mGnssMetrics);
+ mGnssStatusProvider = new GnssStatusProvider(injector, mGnssNative);
+ mGnssNmeaProvider = new GnssNmeaProvider(injector, mGnssNative);
+ mGnssMeasurementsProvider = new GnssMeasurementsProvider(injector, mGnssNative);
+ mGnssAntennaInfoProvider = new GnssAntennaInfoProvider(injector, mGnssNative);
+ mGnssNavigationMessageProvider = new GnssNavigationMessageProvider(injector, mGnssNative);
+ mGnssGeofenceProxy = new GnssGeofenceProxy(mGnssNative);
+
+ mGnssNative.setGeofenceCallbacks(new GnssGeofenceHalModule());
// allow gnss access to begin - we must assume that callbacks can start immediately
- GnssNative.register(this);
+ mGnssNative.register();
}
/** Called when system is ready. */
- public synchronized void onSystemReady() {
+ public void onSystemReady() {
mGnssLocationProvider.onSystemReady();
}
@@ -121,15 +100,15 @@
}
/** Retrieve the IGpsGeofenceHardware. */
- public IGpsGeofenceHardware getGpsGeofenceProxy() {
- return mGpsGeofenceProxy;
+ public IGpsGeofenceHardware getGnssGeofenceProxy() {
+ return mGnssGeofenceProxy;
}
/**
* Get year of GNSS hardware.
*/
public int getGnssYearOfHardware() {
- return mGnssSystemInfoProvider.getGnssYearOfHardware();
+ return mGnssNative.getHardwareYear();
}
/**
@@ -137,15 +116,15 @@
*/
@Nullable
public String getGnssHardwareModelName() {
- return mGnssSystemInfoProvider.getGnssHardwareModelName();
+ return mGnssNative.getHardwareModelName();
}
/**
* Get GNSS hardware capabilities. The capabilities returned are a bitfield as described in
* {@link android.location.GnssCapabilities}.
*/
- public long getGnssCapabilities() {
- return mGnssCapabilitiesProvider.getGnssCapabilities();
+ public GnssCapabilities getGnssCapabilities() {
+ return mGnssNative.getCapabilities();
}
/**
@@ -174,6 +153,24 @@
}
/**
+ * Registers listener for GNSS NMEA messages.
+ */
+ public void registerGnssNmeaCallback(IGnssNmeaListener listener, String packageName,
+ @Nullable String attributionTag) {
+ mContext.enforceCallingOrSelfPermission(Manifest.permission.ACCESS_FINE_LOCATION, null);
+
+ CallerIdentity identity = CallerIdentity.fromBinder(mContext, packageName, attributionTag);
+ mGnssNmeaProvider.addListener(identity, listener);
+ }
+
+ /**
+ * Unregisters listener for GNSS NMEA messages.
+ */
+ public void unregisterGnssNmeaCallback(IGnssNmeaListener listener) {
+ mGnssNmeaProvider.removeListener(listener);
+ }
+
+ /**
* Adds a GNSS measurements listener.
*/
public void addGnssMeasurementsListener(GnssMeasurementRequest request,
@@ -192,7 +189,9 @@
mContext.enforceCallingOrSelfPermission(Manifest.permission.LOCATION_HARDWARE, null);
mContext.enforceCallingOrSelfPermission(Manifest.permission.ACCESS_FINE_LOCATION, null);
- mGnssMeasurementCorrectionsProvider.injectGnssMeasurementCorrections(corrections);
+ if (!mGnssNative.injectMeasurementCorrections(corrections)) {
+ Log.w(TAG, "failed to inject GNSS measurement corrections");
+ }
}
/**
@@ -248,9 +247,9 @@
*/
public void sendNiResponse(int notifId, int userResponse) {
try {
- mNetInitiatedListener.sendNiResponse(notifId, userResponse);
+ mGnssLocationProvider.getNetInitiatedListener().sendNiResponse(notifId, userResponse);
} catch (RemoteException e) {
- Log.e(TAG, "RemoteException in LocationManagerService.sendNiResponse");
+ throw e.rethrowFromSystemServer();
}
}
@@ -259,12 +258,12 @@
*/
public void dump(FileDescriptor fd, IndentingPrintWriter ipw, String[] args) {
if (args.length > 0 && args[0].equals("--gnssmetrics")) {
- if (mGnssMetricsProvider != null) {
- ipw.append(mGnssMetricsProvider.getGnssMetricsAsProtoString());
- }
+ ipw.append(mGnssMetrics.dumpGnssMetricsAsProtoString());
return;
}
+ ipw.println("Capabilities: " + mGnssNative.getCapabilities());
+
ipw.println("Antenna Info Provider:");
ipw.increaseIndent();
mGnssAntennaInfoProvider.dump(fd, ipw, args);
@@ -284,169 +283,92 @@
ipw.increaseIndent();
mGnssStatusProvider.dump(fd, ipw, args);
ipw.decreaseIndent();
+
+ GnssPowerStats powerStats = mGnssNative.getPowerStats();
+ if (powerStats != null) {
+ ipw.println("Last Power Stats:");
+ ipw.increaseIndent();
+ powerStats.dump(fd, ipw, args, mGnssNative.getCapabilities());
+ ipw.decreaseIndent();
+ }
}
- // all native callbacks - to be funneled to various locations as appropriate
+ private class GnssGeofenceHalModule implements GnssNative.GeofenceCallbacks {
- @Override
- public void reportLocation(boolean hasLatLong, Location location) {
- mGnssLocationProvider.reportLocation(hasLatLong, location);
- }
+ private GeofenceHardwareImpl mGeofenceHardwareImpl;
- @Override
- public void reportStatus(int status) {
- mGnssLocationProvider.reportStatus(status);
- }
+ private synchronized GeofenceHardwareImpl getGeofenceHardware() {
+ if (mGeofenceHardwareImpl == null) {
+ mGeofenceHardwareImpl = GeofenceHardwareImpl.getInstance(mContext);
+ }
+ return mGeofenceHardwareImpl;
+ }
- @Override
- public void reportSvStatus(int svCount, int[] svidWithFlags, float[] cn0DbHzs,
- float[] elevations, float[] azimuths, float[] carrierFrequencies,
- float[] basebandCn0DbHzs) {
- mGnssLocationProvider.reportSvStatus(svCount, svidWithFlags, cn0DbHzs, elevations, azimuths,
- carrierFrequencies, basebandCn0DbHzs);
- }
+ @Override
+ public void onReportGeofenceTransition(int geofenceId, Location location,
+ @GeofenceTransition int transition, long timestamp) {
+ FgThread.getHandler().post(() -> getGeofenceHardware().reportGeofenceTransition(
+ geofenceId, location, transition, timestamp,
+ GeofenceHardware.MONITORING_TYPE_GPS_HARDWARE,
+ FusedBatchOptions.SourceTechnologies.GNSS));
+ }
- @Override
- public void reportAGpsStatus(int agpsType, int agpsStatus, byte[] suplIpAddr) {
- mGnssLocationProvider.reportAGpsStatus(agpsType, agpsStatus, suplIpAddr);
- }
+ @Override
+ public void onReportGeofenceStatus(@GeofenceAvailability int status, Location location) {
+ FgThread.getHandler().post(() -> {
+ int monitorStatus = GeofenceHardware.MONITOR_CURRENTLY_UNAVAILABLE;
+ if (status == GEOFENCE_AVAILABILITY_AVAILABLE) {
+ monitorStatus = GeofenceHardware.MONITOR_CURRENTLY_AVAILABLE;
+ }
+ getGeofenceHardware().reportGeofenceMonitorStatus(
+ GeofenceHardware.MONITORING_TYPE_GPS_HARDWARE,
+ monitorStatus,
+ location,
+ FusedBatchOptions.SourceTechnologies.GNSS);
+ });
+ }
- @Override
- public void reportNmea(long timestamp) {
- mGnssLocationProvider.reportNmea(timestamp);
- }
+ @Override
+ public void onReportGeofenceAddStatus(int geofenceId, @GeofenceStatus int status) {
+ FgThread.getHandler().post(() -> getGeofenceHardware().reportGeofenceAddStatus(
+ geofenceId, translateGeofenceStatus(status)));
+ }
- @Override
- public void reportMeasurementData(GnssMeasurementsEvent event) {
- mGnssLocationProvider.reportMeasurementData(event);
- }
+ @Override
+ public void onReportGeofenceRemoveStatus(int geofenceId, @GeofenceStatus int status) {
+ FgThread.getHandler().post(() -> getGeofenceHardware().reportGeofenceRemoveStatus(
+ geofenceId, translateGeofenceStatus(status)));
+ }
- @Override
- public void reportAntennaInfo(List<GnssAntennaInfo> antennaInfos) {
- mGnssLocationProvider.reportAntennaInfo(antennaInfos);
- }
+ @Override
+ public void onReportGeofencePauseStatus(int geofenceId, @GeofenceStatus int status) {
+ FgThread.getHandler().post(() -> getGeofenceHardware().reportGeofencePauseStatus(
+ geofenceId, translateGeofenceStatus(status)));
+ }
- @Override
- public void reportNavigationMessage(GnssNavigationMessage event) {
- mGnssLocationProvider.reportNavigationMessage(event);
- }
+ @Override
+ public void onReportGeofenceResumeStatus(int geofenceId, @GeofenceStatus int status) {
+ FgThread.getHandler().post(() -> getGeofenceHardware().reportGeofenceResumeStatus(
+ geofenceId, translateGeofenceStatus(status)));
+ }
- @Override
- public void reportGnssPowerStats(GnssPowerStats powerStats) {
- mGnssLocationProvider.reportGnssPowerStats(powerStats);
- }
-
- @Override
- public void setTopHalCapabilities(int topHalCapabilities) {
- mGnssLocationProvider.setTopHalCapabilities(topHalCapabilities);
- }
-
- @Override
- public void setSubHalMeasurementCorrectionsCapabilities(int subHalCapabilities) {
- mGnssLocationProvider.setSubHalMeasurementCorrectionsCapabilities(subHalCapabilities);
- }
-
- @Override
- public void setSubHalPowerIndicationCapabilities(int subHalCapabilities) {
- mGnssLocationProvider.setSubHalPowerIndicationCapabilities(subHalCapabilities);
- }
-
- @Override
- public void setGnssYearOfHardware(int yearOfHardware) {
- mGnssLocationProvider.setGnssYearOfHardware(yearOfHardware);
- }
-
- @Override
- public void setGnssHardwareModelName(String modelName) {
- mGnssLocationProvider.setGnssHardwareModelName(modelName);
- }
-
- @Override
- public void reportGnssServiceRestarted() {
- mGnssLocationProvider.reportGnssServiceRestarted();
- }
-
- @Override
- public void reportLocationBatch(Location[] locationArray) {
- mGnssLocationProvider.reportLocationBatch(locationArray);
- }
-
- @Override
- public void psdsDownloadRequest(int psdsType) {
- mGnssLocationProvider.downloadPsdsData(psdsType);
- }
-
- @Override
- public void reportGeofenceTransition(int geofenceId, Location location, int transition,
- long transitionTimestamp) {
- mGnssLocationProvider.reportGeofenceTransition(geofenceId, location, transition,
- transitionTimestamp);
- }
-
- @Override
- public void reportGeofenceStatus(int status, Location location) {
- mGnssLocationProvider.reportGeofenceStatus(status, location);
- }
-
- @Override
- public void reportGeofenceAddStatus(int geofenceId, int status) {
- mGnssLocationProvider.reportGeofenceAddStatus(geofenceId, status);
- }
-
- @Override
- public void reportGeofenceRemoveStatus(int geofenceId, int status) {
- mGnssLocationProvider.reportGeofenceRemoveStatus(geofenceId, status);
- }
-
- @Override
- public void reportGeofencePauseStatus(int geofenceId, int status) {
- mGnssLocationProvider.reportGeofencePauseStatus(geofenceId, status);
- }
-
- @Override
- public void reportGeofenceResumeStatus(int geofenceId, int status) {
- mGnssLocationProvider.reportGeofenceResumeStatus(geofenceId, status);
- }
-
- @Override
- public void reportNiNotification(int notificationId, int niType, int notifyFlags,
- int timeout, int defaultResponse, String requestorId, String text,
- int requestorIdEncoding, int textEncoding) {
- mGnssLocationProvider.reportNiNotification(notificationId, niType, notifyFlags, timeout,
- defaultResponse, requestorId, text, requestorIdEncoding, textEncoding);
- }
-
- @Override
- public void requestSetID(int flags) {
- mGnssLocationProvider.requestSetID(flags);
- }
-
- @Override
- public void requestLocation(boolean independentFromGnss, boolean isUserEmergency) {
- mGnssLocationProvider.requestLocation(independentFromGnss, isUserEmergency);
- }
-
- @Override
- public void requestUtcTime() {
- mGnssLocationProvider.requestUtcTime();
- }
-
- @Override
- public void requestRefLocation() {
- mGnssLocationProvider.requestRefLocation();
- }
-
- @Override
- public void reportNfwNotification(String proxyAppPackageName, byte protocolStack,
- String otherProtocolStackName, byte requestor, String requestorId,
- byte responseType, boolean inEmergencyMode, boolean isCachedLocation) {
- mGnssLocationProvider.reportNfwNotification(proxyAppPackageName, protocolStack,
- otherProtocolStackName, requestor, requestorId, responseType, inEmergencyMode,
- isCachedLocation);
- }
-
- @Override
- public boolean isInEmergencySession() {
- return mGnssLocationProvider.isInEmergencySession();
+ private int translateGeofenceStatus(@GeofenceStatus int status) {
+ switch (status) {
+ case GEOFENCE_STATUS_OPERATION_SUCCESS:
+ return GeofenceHardware.GEOFENCE_SUCCESS;
+ case GEOFENCE_STATUS_ERROR_GENERIC:
+ return GeofenceHardware.GEOFENCE_FAILURE;
+ case GEOFENCE_STATUS_ERROR_ID_EXISTS:
+ return GeofenceHardware.GEOFENCE_ERROR_ID_EXISTS;
+ case GEOFENCE_STATUS_ERROR_INVALID_TRANSITION:
+ return GeofenceHardware.GEOFENCE_ERROR_INVALID_TRANSITION;
+ case GEOFENCE_STATUS_ERROR_TOO_MANY_GEOFENCES:
+ return GeofenceHardware.GEOFENCE_ERROR_TOO_MANY_GEOFENCES;
+ case GEOFENCE_STATUS_ERROR_ID_UNKNOWN:
+ return GeofenceHardware.GEOFENCE_ERROR_ID_UNKNOWN;
+ default:
+ return -1;
+ }
+ }
}
}
diff --git a/services/core/java/com/android/server/location/gnss/GnssMeasurementCorrectionsProvider.java b/services/core/java/com/android/server/location/gnss/GnssMeasurementCorrectionsProvider.java
deleted file mode 100644
index 4401f29..0000000
--- a/services/core/java/com/android/server/location/gnss/GnssMeasurementCorrectionsProvider.java
+++ /dev/null
@@ -1,151 +0,0 @@
-/*
- * Copyright (C) 2020 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.server.location.gnss;
-
-import android.location.GnssMeasurementCorrections;
-import android.os.Handler;
-import android.util.Log;
-
-import com.android.internal.annotations.VisibleForTesting;
-
-/**
- * Manages GNSS measurement corrections.
- *
- * <p>Implements the framework side of the GNSS HAL interfaces {@code IMeasurementCorrections.hal}
- * and {@code IMeasurementCorrectionsCallback.hal).
- *
- * @hide
- */
-public class GnssMeasurementCorrectionsProvider {
- private static final String TAG = "GnssMeasurementCorrectionsProvider";
-
- // These must match with the Capabilities enum in IMeasurementCorrectionsCallback.hal.
- static final int CAPABILITY_LOS_SATS = 0x0000001;
- static final int CAPABILITY_EXCESS_PATH_LENGTH = 0x0000002;
- static final int CAPABILITY_REFLECTING_PLANE = 0x0000004;
-
- private static final int INVALID_CAPABILITIES = 1 << 31;
-
- private final Handler mHandler;
- private final GnssMeasurementCorrectionsProviderNative mNative;
- private volatile int mCapabilities = INVALID_CAPABILITIES;
-
- GnssMeasurementCorrectionsProvider(Handler handler) {
- this(handler, new GnssMeasurementCorrectionsProviderNative());
- }
-
- @VisibleForTesting
- GnssMeasurementCorrectionsProvider(Handler handler,
- GnssMeasurementCorrectionsProviderNative aNative) {
- mHandler = handler;
- mNative = aNative;
- }
-
- /**
- * Returns {@code true} if the GNSS HAL implementation supports measurement corrections.
- */
- public boolean isAvailableInPlatform() {
- return mNative.isMeasurementCorrectionsSupported();
- }
-
- /**
- * Injects GNSS measurement corrections into the GNSS chipset.
- *
- * @param measurementCorrections a {@link GnssMeasurementCorrections} object with the GNSS
- * measurement corrections to be injected into the GNSS chipset.
- */
- public void injectGnssMeasurementCorrections(
- GnssMeasurementCorrections measurementCorrections) {
- if (!isCapabilitiesReceived()) {
- Log.w(TAG, "Failed to inject GNSS measurement corrections. Capabilities "
- + "not received yet.");
- return;
- }
- mHandler.post(() -> {
- if (!mNative.injectGnssMeasurementCorrections(measurementCorrections)) {
- Log.e(TAG, "Failure in injecting GNSS corrections.");
- }
- });
- }
-
- /** Handle measurement corrections capabilities update from the GNSS HAL implementation. */
- boolean onCapabilitiesUpdated(int capabilities) {
- if (hasCapability(capabilities, CAPABILITY_LOS_SATS) || hasCapability(capabilities,
- CAPABILITY_EXCESS_PATH_LENGTH)) {
- mCapabilities = capabilities;
- return true;
- } else {
- Log.e(TAG, "Failed to set capabilities. Received capabilities 0x"
- + Integer.toHexString(capabilities) + " does not contain the mandatory "
- + "LOS_SATS or the EXCESS_PATH_LENGTH capability.");
- return false;
- }
- }
-
- /**
- * Returns the measurement corrections specific capabilities of the GNSS HAL implementation.
- */
- int getCapabilities() {
- return mCapabilities;
- }
-
- /**
- * Returns the string representation of the GNSS measurement capabilities.
- */
- String toStringCapabilities() {
- final int capabilities = getCapabilities();
- StringBuilder s = new StringBuilder();
- s.append("mCapabilities=0x").append(Integer.toHexString(capabilities));
- s.append(" ( ");
- if (hasCapability(capabilities, CAPABILITY_LOS_SATS)) {
- s.append("LOS_SATS ");
- }
- if (hasCapability(capabilities, CAPABILITY_EXCESS_PATH_LENGTH)) {
- s.append("EXCESS_PATH_LENGTH ");
- }
- if (hasCapability(capabilities, CAPABILITY_REFLECTING_PLANE)) {
- s.append("REFLECTING_PLANE ");
- }
- s.append(")");
- return s.toString();
- }
-
- private static boolean hasCapability(int halCapabilities, int capability) {
- return (halCapabilities & capability) != 0;
- }
-
- private boolean isCapabilitiesReceived() {
- return mCapabilities != INVALID_CAPABILITIES;
- }
-
- @VisibleForTesting
- static class GnssMeasurementCorrectionsProviderNative {
- public boolean isMeasurementCorrectionsSupported() {
- return native_is_measurement_corrections_supported();
- }
-
- public boolean injectGnssMeasurementCorrections(
- GnssMeasurementCorrections measurementCorrections) {
- return native_inject_gnss_measurement_corrections(measurementCorrections);
- }
- }
-
- static native boolean native_is_measurement_corrections_supported();
-
- static native boolean native_inject_gnss_measurement_corrections(
- GnssMeasurementCorrections measurementCorrections);
-}
diff --git a/services/core/java/com/android/server/location/gnss/GnssMeasurementsProvider.java b/services/core/java/com/android/server/location/gnss/GnssMeasurementsProvider.java
index fa8e2a6..b7cc9f5 100644
--- a/services/core/java/com/android/server/location/gnss/GnssMeasurementsProvider.java
+++ b/services/core/java/com/android/server/location/gnss/GnssMeasurementsProvider.java
@@ -21,6 +21,7 @@
import android.annotation.Nullable;
import android.app.AppOpsManager;
+import android.location.GnssCapabilities;
import android.location.GnssMeasurementRequest;
import android.location.GnssMeasurementsEvent;
import android.location.IGnssMeasurementsListener;
@@ -29,8 +30,7 @@
import android.stats.location.LocationStatsEnums;
import android.util.Log;
-import com.android.internal.annotations.VisibleForTesting;
-import com.android.internal.util.Preconditions;
+import com.android.server.location.gnss.hal.GnssNative;
import com.android.server.location.injector.AppOpsHelper;
import com.android.server.location.injector.Injector;
import com.android.server.location.injector.LocationAttributionHelper;
@@ -38,7 +38,6 @@
import com.android.server.location.injector.SettingsHelper;
import java.util.Collection;
-import java.util.Objects;
/**
* An base implementation for GNSS measurements provider. It abstracts out the responsibility of
@@ -47,8 +46,10 @@
* @hide
*/
public final class GnssMeasurementsProvider extends
- GnssListenerMultiplexer<GnssMeasurementRequest, IGnssMeasurementsListener, Boolean>
- implements SettingsHelper.GlobalSettingChangedListener {
+ GnssListenerMultiplexer<GnssMeasurementRequest, IGnssMeasurementsListener,
+ GnssMeasurementRequest> implements
+ SettingsHelper.GlobalSettingChangedListener, GnssNative.BaseCallbacks,
+ GnssNative.MeasurementCallbacks {
private class GnssMeasurementListenerRegistration extends GnssListenerRegistration {
@@ -79,24 +80,22 @@
private final AppOpsHelper mAppOpsHelper;
private final LocationAttributionHelper mLocationAttributionHelper;
private final LocationUsageLogger mLogger;
- private final GnssMeasurementProviderNative mNative;
+ private final GnssNative mGnssNative;
- public GnssMeasurementsProvider(Injector injector) {
- this(injector, new GnssMeasurementProviderNative());
- }
-
- @VisibleForTesting
- public GnssMeasurementsProvider(Injector injector, GnssMeasurementProviderNative aNative) {
+ public GnssMeasurementsProvider(Injector injector, GnssNative gnssNative) {
super(injector);
mAppOpsHelper = injector.getAppOpsHelper();
mLocationAttributionHelper = injector.getLocationAttributionHelper();
mLogger = injector.getLocationUsageLogger();
- mNative = aNative;
+ mGnssNative = gnssNative;
+
+ mGnssNative.addBaseCallbacks(this);
+ mGnssNative.addMeasurementCallbacks(this);
}
@Override
protected boolean isServiceSupported() {
- return mNative.isMeasurementSupported();
+ return mGnssNative.isMeasurementSupported();
}
@Override
@@ -112,17 +111,14 @@
}
@Override
- protected boolean registerWithService(Boolean fullTrackingRequest,
+ protected boolean registerWithService(GnssMeasurementRequest request,
Collection<GnssListenerRegistration> registrations) {
- Preconditions.checkState(mNative.isMeasurementSupported());
-
- if (mNative.startMeasurementCollection(fullTrackingRequest)) {
+ if (mGnssNative.startMeasurementCollection(request.isFullTracking())) {
if (D) {
- Log.d(TAG, "starting gnss measurements (" + fullTrackingRequest + ")");
+ Log.d(TAG, "starting gnss measurements (" + request + ")");
}
return true;
} else {
-
Log.e(TAG, "error starting gnss measurements");
return false;
}
@@ -130,14 +126,12 @@
@Override
protected void unregisterWithService() {
- if (mNative.isMeasurementSupported()) {
- if (mNative.stopMeasurementCollection()) {
- if (D) {
- Log.d(TAG, "stopping gnss measurements");
- }
- } else {
- Log.e(TAG, "error stopping gnss measurements");
+ if (mGnssNative.stopMeasurementCollection()) {
+ if (D) {
+ Log.d(TAG, "stopping gnss measurements");
}
+ } else {
+ Log.e(TAG, "error stopping gnss measurements");
}
}
@@ -158,18 +152,21 @@
}
@Override
- protected Boolean mergeRegistrations(Collection<GnssListenerRegistration> registrations) {
+ protected GnssMeasurementRequest mergeRegistrations(
+ Collection<GnssListenerRegistration> registrations) {
+ boolean fullTracking = false;
if (mSettingsHelper.isGnssMeasurementsFullTrackingEnabled()) {
- return true;
- }
-
- for (GnssListenerRegistration registration : registrations) {
- if (Objects.requireNonNull(registration.getRequest()).isFullTracking()) {
- return true;
+ fullTracking = true;
+ } else {
+ for (GnssListenerRegistration registration : registrations) {
+ if (registration.getRequest().isFullTracking()) {
+ fullTracking = true;
+ break;
+ }
}
}
- return false;
+ return new GnssMeasurementRequest.Builder().setFullTracking(fullTracking).build();
}
@Override
@@ -198,10 +195,17 @@
null, registration.isForeground());
}
- /**
- * Called by GnssLocationProvider.
- */
- public void onMeasurementsAvailable(GnssMeasurementsEvent event) {
+ @Override
+ public void onHalRestarted() {
+ resetService();
+ }
+
+ @Override
+ public void onCapabilitiesChanged(GnssCapabilities oldCapabilities,
+ GnssCapabilities newCapabilities) {}
+
+ @Override
+ public void onReportMeasurements(GnssMeasurementsEvent event) {
deliverToListeners(registration -> {
if (mAppOpsHelper.noteOpNoThrow(AppOpsManager.OP_FINE_LOCATION,
registration.getIdentity())) {
@@ -211,25 +215,4 @@
}
});
}
-
- @VisibleForTesting
- static class GnssMeasurementProviderNative {
- boolean isMeasurementSupported() {
- return native_is_measurement_supported();
- }
-
- boolean startMeasurementCollection(boolean enableFullTracking) {
- return native_start_measurement_collection(enableFullTracking);
- }
-
- boolean stopMeasurementCollection() {
- return native_stop_measurement_collection();
- }
- }
-
- static native boolean native_is_measurement_supported();
-
- static native boolean native_start_measurement_collection(boolean enableFullTracking);
-
- static native boolean native_stop_measurement_collection();
}
diff --git a/location/java/com/android/internal/location/gnssmetrics/GnssMetrics.java b/services/core/java/com/android/server/location/gnss/GnssMetrics.java
similarity index 95%
rename from location/java/com/android/internal/location/gnssmetrics/GnssMetrics.java
rename to services/core/java/com/android/server/location/gnss/GnssMetrics.java
index dd8a8c3..c7d8144 100644
--- a/location/java/com/android/internal/location/gnssmetrics/GnssMetrics.java
+++ b/services/core/java/com/android/server/location/gnss/GnssMetrics.java
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2016 The Android Open Source Project
+ * Copyright (C) 2020 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -14,15 +14,11 @@
* limitations under the License.
*/
-package com.android.internal.location.gnssmetrics;
-
-import static android.location.GnssSignalQuality.GNSS_SIGNAL_QUALITY_GOOD;
-import static android.location.GnssSignalQuality.GNSS_SIGNAL_QUALITY_POOR;
-import static android.location.GnssSignalQuality.GNSS_SIGNAL_QUALITY_UNKNOWN;
-import static android.location.GnssSignalQuality.NUM_GNSS_SIGNAL_QUALITY_LEVELS;
+package com.android.server.location.gnss;
import android.app.StatsManager;
import android.content.Context;
+import android.location.GnssSignalQuality;
import android.location.GnssStatus;
import android.os.RemoteException;
import android.os.SystemClock;
@@ -67,11 +63,11 @@
// A boolean array indicating whether the constellation types have been used in fix.
private boolean[] mConstellationTypes;
- private Statistics mLocationFailureStatistics;
- private Statistics mTimeToFirstFixSecStatistics;
- private Statistics mPositionAccuracyMeterStatistics;
- private Statistics mTopFourAverageCn0Statistics;
- private Statistics mTopFourAverageCn0StatisticsL5;
+ private final Statistics mLocationFailureStatistics;
+ private final Statistics mTimeToFirstFixSecStatistics;
+ private final Statistics mPositionAccuracyMeterStatistics;
+ private final Statistics mTopFourAverageCn0Statistics;
+ private final Statistics mTopFourAverageCn0StatisticsL5;
// Total number of sv status messages processed
private int mNumSvStatus;
// Total number of L5 sv status messages processed
@@ -91,7 +87,7 @@
long mSvStatusReportsUsedInFix;
long mL5SvStatusReportsUsedInFix;
- private StatsManager mStatsManager;
+ private final StatsManager mStatsManager;
public GnssMetrics(Context context, IBatteryStats stats) {
mGnssPowerMetrics = new GnssPowerMetrics(stats);
@@ -390,7 +386,7 @@
stats.getLoggingDurationMs() / ((double) DateUtils.MINUTE_IN_MILLIS)).append(
"\n");
long[] t = stats.getTimeInGpsSignalQualityLevel();
- if (t != null && t.length == NUM_GNSS_SIGNAL_QUALITY_LEVELS) {
+ if (t != null && t.length == GnssSignalQuality.NUM_GNSS_SIGNAL_QUALITY_LEVELS) {
s.append(" Amount of time (while on battery) Top 4 Avg CN0 > "
+ GnssPowerMetrics.POOR_TOP_FOUR_AVG_CN0_THRESHOLD_DB_HZ
+ " dB-Hz (min): ").append(
@@ -505,7 +501,7 @@
// so that
// the first CNO report will trigger an update to BatteryStats
mLastAverageCn0 = -100.0;
- mLastSignalLevel = GNSS_SIGNAL_QUALITY_UNKNOWN;
+ mLastSignalLevel = GnssSignalQuality.GNSS_SIGNAL_QUALITY_UNKNOWN;
}
/**
@@ -577,9 +573,9 @@
*/
private int getSignalLevel(double cn0) {
if (cn0 > POOR_TOP_FOUR_AVG_CN0_THRESHOLD_DB_HZ) {
- return GNSS_SIGNAL_QUALITY_GOOD;
+ return GnssSignalQuality.GNSS_SIGNAL_QUALITY_GOOD;
}
- return GNSS_SIGNAL_QUALITY_POOR;
+ return GnssSignalQuality.GNSS_SIGNAL_QUALITY_POOR;
}
}
diff --git a/services/core/java/com/android/server/location/gnss/GnssNative.java b/services/core/java/com/android/server/location/gnss/GnssNative.java
deleted file mode 100644
index 4494c19..0000000
--- a/services/core/java/com/android/server/location/gnss/GnssNative.java
+++ /dev/null
@@ -1,324 +0,0 @@
-/*
- * Copyright (C) 2020 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.server.location.gnss;
-
-import android.location.GnssAntennaInfo;
-import android.location.GnssMeasurementsEvent;
-import android.location.GnssNavigationMessage;
-import android.location.Location;
-
-import com.android.internal.annotations.GuardedBy;
-import com.android.internal.annotations.VisibleForTesting;
-import com.android.internal.util.Preconditions;
-import com.android.server.FgThread;
-
-import java.lang.annotation.ElementType;
-import java.lang.annotation.Retention;
-import java.lang.annotation.RetentionPolicy;
-import java.lang.annotation.Target;
-import java.util.List;
-
-/**
- * Entry point for all GNSS native callbacks, and responsible for initializing the GNSS HAL.
- */
-class GnssNative {
-
- interface Callbacks {
- void reportLocation(boolean hasLatLong, Location location);
- void reportStatus(int status);
- void reportSvStatus(int svCount, int[] svidWithFlags, float[] cn0DbHzs,
- float[] elevations, float[] azimuths, float[] carrierFrequencies,
- float[] basebandCn0DbHzs);
- void reportAGpsStatus(int agpsType, int agpsStatus, byte[] suplIpAddr);
- void reportNmea(long timestamp);
- void reportMeasurementData(GnssMeasurementsEvent event);
- void reportAntennaInfo(List<GnssAntennaInfo> antennaInfos);
- void reportNavigationMessage(GnssNavigationMessage event);
- void reportGnssPowerStats(GnssPowerStats powerStats);
- void setTopHalCapabilities(int topHalCapabilities);
- void setSubHalMeasurementCorrectionsCapabilities(int subHalCapabilities);
- void setSubHalPowerIndicationCapabilities(int subHalCapabilities);
- void setGnssYearOfHardware(int yearOfHardware);
- void setGnssHardwareModelName(String modelName);
- void reportGnssServiceRestarted();
- void reportLocationBatch(Location[] locationArray);
- void psdsDownloadRequest(int psdsType);
- void reportGeofenceTransition(int geofenceId, Location location, int transition,
- long transitionTimestamp);
- void reportGeofenceStatus(int status, Location location);
- void reportGeofenceAddStatus(int geofenceId, int status);
- void reportGeofenceRemoveStatus(int geofenceId, int status);
- void reportGeofencePauseStatus(int geofenceId, int status);
- void reportGeofenceResumeStatus(int geofenceId, int status);
- void reportNiNotification(
- int notificationId,
- int niType,
- int notifyFlags,
- int timeout,
- int defaultResponse,
- String requestorId,
- String text,
- int requestorIdEncoding,
- int textEncoding
- );
- void requestSetID(int flags);
- void requestLocation(boolean independentFromGnss, boolean isUserEmergency);
- void requestUtcTime();
- void requestRefLocation();
- void reportNfwNotification(String proxyAppPackageName, byte protocolStack,
- String otherProtocolStackName, byte requestor, String requestorId,
- byte responseType, boolean inEmergencyMode, boolean isCachedLocation);
- boolean isInEmergencySession();
- }
-
- /**
- * 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 {}
-
- @GuardedBy("GnssNative.class")
- private static boolean sInitialized;
-
- @GuardedBy("GnssNative.class")
- private static GnssNativeInitNative sInitNative = new GnssNativeInitNative();
-
- @GuardedBy("GnssNative.class")
- private static GnssNative sInstance;
-
- @VisibleForTesting
- public static synchronized void setInitNativeForTest(GnssNativeInitNative initNative) {
- sInitNative = initNative;
- }
-
- public static synchronized boolean isSupported() {
- initialize();
- return sInitNative.isSupported();
- }
-
- static synchronized void initialize() {
- if (!sInitialized) {
- sInitNative.classInitOnce();
- sInitialized = true;
- }
- }
-
- @VisibleForTesting
- public static synchronized void resetCallbacksForTest() {
- sInstance = null;
- }
-
- static synchronized void register(Callbacks callbacks) {
- Preconditions.checkState(sInstance == null);
- initialize();
- sInstance = new GnssNative(callbacks);
- }
-
- private final Callbacks mCallbacks;
-
- private GnssNative(Callbacks callbacks) {
- mCallbacks = callbacks;
- sInitNative.initOnce(this, false);
- }
-
- @NativeEntryPoint
- private void reportLocation(boolean hasLatLong, Location location) {
- mCallbacks.reportLocation(hasLatLong, location);
- }
-
- @NativeEntryPoint
- private void reportStatus(int status) {
- mCallbacks.reportStatus(status);
- }
-
- @NativeEntryPoint
- private void reportSvStatus(int svCount, int[] svidWithFlags, float[] cn0DbHzs,
- float[] elevations, float[] azimuths, float[] carrierFrequencies,
- float[] basebandCn0DbHzs) {
- mCallbacks.reportSvStatus(svCount, svidWithFlags, cn0DbHzs, elevations, azimuths,
- carrierFrequencies, basebandCn0DbHzs);
- }
-
- @NativeEntryPoint
- private void reportAGpsStatus(int agpsType, int agpsStatus, byte[] suplIpAddr) {
- mCallbacks.reportAGpsStatus(agpsType, agpsStatus, suplIpAddr);
- }
-
- @NativeEntryPoint
- private void reportNmea(long timestamp) {
- mCallbacks.reportNmea(timestamp);
- }
-
- @NativeEntryPoint
- private void reportMeasurementData(GnssMeasurementsEvent event) {
- mCallbacks.reportMeasurementData(event);
- }
-
- @NativeEntryPoint
- private void reportAntennaInfo(List<GnssAntennaInfo> antennaInfos) {
- mCallbacks.reportAntennaInfo(antennaInfos);
- }
-
- @NativeEntryPoint
- private void reportNavigationMessage(GnssNavigationMessage event) {
- mCallbacks.reportNavigationMessage(event);
- }
-
- @NativeEntryPoint
- private void reportGnssPowerStats(GnssPowerStats powerStats) {
- mCallbacks.reportGnssPowerStats(powerStats);
- }
-
- @NativeEntryPoint
- private void setTopHalCapabilities(int topHalCapabilities) {
- mCallbacks.setTopHalCapabilities(topHalCapabilities);
- }
-
- @NativeEntryPoint
- private void setSubHalMeasurementCorrectionsCapabilities(int subHalCapabilities) {
- mCallbacks.setSubHalMeasurementCorrectionsCapabilities(subHalCapabilities);
- }
-
- @NativeEntryPoint
- private void setSubHalPowerIndicationCapabilities(int subHalCapabilities) {
- mCallbacks.setSubHalPowerIndicationCapabilities(subHalCapabilities);
- }
-
- @NativeEntryPoint
- private void setGnssYearOfHardware(int yearOfHardware) {
- mCallbacks.setGnssYearOfHardware(yearOfHardware);
- }
-
- @NativeEntryPoint
- private void setGnssHardwareModelName(String modelName) {
- mCallbacks.setGnssHardwareModelName(modelName);
- }
-
- @NativeEntryPoint
- private void reportGnssServiceDied() {
- FgThread.getExecutor().execute(() -> {
- sInitNative.initOnce(GnssNative.this, true);
- mCallbacks.reportGnssServiceRestarted();
- });
- }
-
- @NativeEntryPoint
- private void reportLocationBatch(Location[] locationArray) {
- mCallbacks.reportLocationBatch(locationArray);
- }
-
- @NativeEntryPoint
- private void psdsDownloadRequest(int psdsType) {
- mCallbacks.psdsDownloadRequest(psdsType);
- }
-
- @NativeEntryPoint
- private void reportGeofenceTransition(int geofenceId, Location location, int transition,
- long transitionTimestamp) {
- mCallbacks.reportGeofenceTransition(geofenceId, location, transition, transitionTimestamp);
- }
-
- @NativeEntryPoint
- private void reportGeofenceStatus(int status, Location location) {
- mCallbacks.reportGeofenceStatus(status, location);
- }
-
- @NativeEntryPoint
- private void reportGeofenceAddStatus(int geofenceId, int status) {
- mCallbacks.reportGeofenceAddStatus(geofenceId, status);
- }
-
- @NativeEntryPoint
- private void reportGeofenceRemoveStatus(int geofenceId, int status) {
- mCallbacks.reportGeofenceRemoveStatus(geofenceId, status);
- }
-
- @NativeEntryPoint
- private void reportGeofencePauseStatus(int geofenceId, int status) {
- mCallbacks.reportGeofencePauseStatus(geofenceId, status);
- }
-
- @NativeEntryPoint
- private void reportGeofenceResumeStatus(int geofenceId, int status) {
- mCallbacks.reportGeofenceResumeStatus(geofenceId, status);
- }
-
- @NativeEntryPoint
- private void reportNiNotification(int notificationId, int niType, int notifyFlags,
- int timeout, int defaultResponse, String requestorId, String text,
- int requestorIdEncoding, int textEncoding) {
- mCallbacks.reportNiNotification(notificationId, niType, notifyFlags, timeout,
- defaultResponse, requestorId, text, requestorIdEncoding, textEncoding);
- }
-
- @NativeEntryPoint
- private void requestSetID(int flags) {
- mCallbacks.requestSetID(flags);
- }
-
- @NativeEntryPoint
- private void requestLocation(boolean independentFromGnss, boolean isUserEmergency) {
- mCallbacks.requestLocation(independentFromGnss, isUserEmergency);
- }
-
- @NativeEntryPoint
- private void requestUtcTime() {
- mCallbacks.requestUtcTime();
- }
-
- @NativeEntryPoint
- private void requestRefLocation() {
- mCallbacks.requestRefLocation();
- }
-
- @NativeEntryPoint
- private void reportNfwNotification(String proxyAppPackageName, byte protocolStack,
- String otherProtocolStackName, byte requestor, String requestorId,
- byte responseType, boolean inEmergencyMode, boolean isCachedLocation) {
- mCallbacks.reportNfwNotification(proxyAppPackageName, protocolStack, otherProtocolStackName,
- requestor, requestorId, responseType, inEmergencyMode, isCachedLocation);
- }
-
- @NativeEntryPoint
- private boolean isInEmergencySession() {
- return mCallbacks.isInEmergencySession();
- }
-
- @VisibleForTesting
- public static class GnssNativeInitNative {
-
- public void classInitOnce() {
- native_class_init_once();
- }
-
- public boolean isSupported() {
- return native_is_supported();
- }
-
- public void initOnce(GnssNative gnssNative, boolean reinitializeGnssServiceHandle) {
- gnssNative.native_init_once(reinitializeGnssServiceHandle);
- }
- }
-
- static native void native_class_init_once();
-
- static native boolean native_is_supported();
-
- native void native_init_once(boolean reinitializeGnssServiceHandle);
-}
diff --git a/services/core/java/com/android/server/location/gnss/GnssNavigationMessageProvider.java b/services/core/java/com/android/server/location/gnss/GnssNavigationMessageProvider.java
index 92491f7..9b1cde0 100644
--- a/services/core/java/com/android/server/location/gnss/GnssNavigationMessageProvider.java
+++ b/services/core/java/com/android/server/location/gnss/GnssNavigationMessageProvider.java
@@ -20,13 +20,13 @@
import static com.android.server.location.gnss.GnssManagerService.TAG;
import android.app.AppOpsManager;
+import android.location.GnssCapabilities;
import android.location.GnssNavigationMessage;
import android.location.IGnssNavigationMessageListener;
import android.location.util.identity.CallerIdentity;
import android.util.Log;
-import com.android.internal.annotations.VisibleForTesting;
-import com.android.internal.util.Preconditions;
+import com.android.server.location.gnss.hal.GnssNative;
import com.android.server.location.injector.AppOpsHelper;
import com.android.server.location.injector.Injector;
@@ -40,21 +40,24 @@
* @hide
*/
public class GnssNavigationMessageProvider extends
- GnssListenerMultiplexer<Void, IGnssNavigationMessageListener, Void> {
+ GnssListenerMultiplexer<Void, IGnssNavigationMessageListener, Void> implements
+ GnssNative.BaseCallbacks, GnssNative.NavigationMessageCallbacks {
private final AppOpsHelper mAppOpsHelper;
- private final GnssNavigationMessageProviderNative mNative;
+ private final GnssNative mGnssNative;
- public GnssNavigationMessageProvider(Injector injector) {
- this(injector, new GnssNavigationMessageProviderNative());
- }
-
- @VisibleForTesting
- public GnssNavigationMessageProvider(Injector injector,
- GnssNavigationMessageProviderNative aNative) {
+ public GnssNavigationMessageProvider(Injector injector, GnssNative gnssNative) {
super(injector);
mAppOpsHelper = injector.getAppOpsHelper();
- mNative = aNative;
+ mGnssNative = gnssNative;
+
+ mGnssNative.addBaseCallbacks(this);
+ mGnssNative.addNavigationMessageCallbacks(this);
+ }
+
+ @Override
+ protected boolean isServiceSupported() {
+ return mGnssNative.isNavigationMessageCollectionSupported();
}
@Override
@@ -65,9 +68,7 @@
@Override
protected boolean registerWithService(Void ignored,
Collection<GnssListenerRegistration> registrations) {
- Preconditions.checkState(mNative.isNavigationMessageSupported());
-
- if (mNative.startNavigationMessageCollection()) {
+ if (mGnssNative.startNavigationMessageCollection()) {
if (D) {
Log.d(TAG, "starting gnss navigation messages");
}
@@ -80,21 +81,26 @@
@Override
protected void unregisterWithService() {
- if (mNative.isNavigationMessageSupported()) {
- if (mNative.stopNavigationMessageCollection()) {
- if (D) {
- Log.d(TAG, "stopping gnss navigation messages");
- }
- } else {
- Log.e(TAG, "error stopping gnss navigation messages");
+ if (mGnssNative.stopNavigationMessageCollection()) {
+ if (D) {
+ Log.d(TAG, "stopping gnss navigation messages");
}
+ } else {
+ Log.e(TAG, "error stopping gnss navigation messages");
}
}
- /**
- * Called by GnssLocationProvider.
- */
- public void onNavigationMessageAvailable(GnssNavigationMessage event) {
+ @Override
+ public void onHalRestarted() {
+ resetService();
+ }
+
+ @Override
+ public void onCapabilitiesChanged(GnssCapabilities oldCapabilities,
+ GnssCapabilities newCapabilities) {}
+
+ @Override
+ public void onReportNavigationMessage(GnssNavigationMessage event) {
deliverToListeners(registration -> {
if (mAppOpsHelper.noteOpNoThrow(AppOpsManager.OP_FINE_LOCATION,
registration.getIdentity())) {
@@ -104,30 +110,4 @@
}
});
}
-
- @Override
- protected boolean isServiceSupported() {
- return mNative.isNavigationMessageSupported();
- }
-
- @VisibleForTesting
- static class GnssNavigationMessageProviderNative {
- boolean isNavigationMessageSupported() {
- return native_is_navigation_message_supported();
- }
-
- boolean startNavigationMessageCollection() {
- return native_start_navigation_message_collection();
- }
-
- boolean stopNavigationMessageCollection() {
- return native_stop_navigation_message_collection();
- }
- }
-
- static native boolean native_is_navigation_message_supported();
-
- static native boolean native_start_navigation_message_collection();
-
- static native boolean native_stop_navigation_message_collection();
}
diff --git a/services/core/java/com/android/server/location/gnss/GnssNmeaProvider.java b/services/core/java/com/android/server/location/gnss/GnssNmeaProvider.java
new file mode 100644
index 0000000..bad1b79
--- /dev/null
+++ b/services/core/java/com/android/server/location/gnss/GnssNmeaProvider.java
@@ -0,0 +1,115 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.location.gnss;
+
+import static com.android.server.location.gnss.GnssManagerService.D;
+import static com.android.server.location.gnss.GnssManagerService.TAG;
+
+import android.annotation.Nullable;
+import android.app.AppOpsManager;
+import android.location.GnssCapabilities;
+import android.location.IGnssNmeaListener;
+import android.location.util.identity.CallerIdentity;
+import android.util.Log;
+
+import com.android.internal.listeners.ListenerExecutor;
+import com.android.server.location.gnss.hal.GnssNative;
+import com.android.server.location.injector.AppOpsHelper;
+import com.android.server.location.injector.Injector;
+
+import java.util.Collection;
+import java.util.function.Function;
+
+/**
+ * Implementation of a handler for {@link IGnssNmeaListener}.
+ */
+class GnssNmeaProvider extends GnssListenerMultiplexer<Void, IGnssNmeaListener, Void> implements
+ GnssNative.BaseCallbacks, GnssNative.NmeaCallbacks {
+
+ private final AppOpsHelper mAppOpsHelper;
+ private final GnssNative mGnssNative;
+
+ // preallocated to avoid memory allocation in onReportNmea()
+ private final byte[] mNmeaBuffer = new byte[120];
+
+ GnssNmeaProvider(Injector injector, GnssNative gnssNative) {
+ super(injector);
+
+ mAppOpsHelper = injector.getAppOpsHelper();
+ mGnssNative = gnssNative;
+
+ mGnssNative.addBaseCallbacks(this);
+ mGnssNative.addNmeaCallbacks(this);
+ }
+
+ @Override
+ public void addListener(CallerIdentity identity, IGnssNmeaListener listener) {
+ super.addListener(identity, listener);
+ }
+
+ @Override
+ protected boolean registerWithService(Void ignored,
+ Collection<GnssListenerRegistration> registrations) {
+ if (D) {
+ Log.d(TAG, "starting gnss nmea messages");
+ }
+ return true;
+ }
+
+ @Override
+ protected void unregisterWithService() {
+ if (D) {
+ Log.d(TAG, "stopping gnss nmea messages");
+ }
+ }
+
+ @Override
+ public void onHalRestarted() {
+ resetService();
+ }
+
+ @Override
+ public void onCapabilitiesChanged(GnssCapabilities oldCapabilities,
+ GnssCapabilities newCapabilities) {}
+
+ @Override
+ public void onReportNmea(long timestamp) {
+ deliverToListeners(
+ new Function<GnssListenerRegistration,
+ ListenerExecutor.ListenerOperation<IGnssNmeaListener>>() {
+
+ // only read in the nmea string if we need to
+ private @Nullable String mNmea;
+
+ @Override
+ public ListenerExecutor.ListenerOperation<IGnssNmeaListener> apply(
+ GnssListenerRegistration registration) {
+ if (mAppOpsHelper.noteOpNoThrow(AppOpsManager.OP_FINE_LOCATION,
+ registration.getIdentity())) {
+ if (mNmea == null) {
+ int length = mGnssNative.readNmea(mNmeaBuffer,
+ mNmeaBuffer.length);
+ mNmea = new String(mNmeaBuffer, 0, length);
+ }
+ return listener -> listener.onNmeaReceived(timestamp, mNmea);
+ } else {
+ return null;
+ }
+ }
+ });
+ }
+}
diff --git a/services/core/java/com/android/server/location/gnss/GnssPowerIndicationProvider.java b/services/core/java/com/android/server/location/gnss/GnssPowerIndicationProvider.java
deleted file mode 100644
index 5941a33..0000000
--- a/services/core/java/com/android/server/location/gnss/GnssPowerIndicationProvider.java
+++ /dev/null
@@ -1,122 +0,0 @@
-/*
- * Copyright (C) 2020 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.server.location.gnss;
-
-import static android.hardware.gnss.IGnssPowerIndicationCallback.CAPABILITY_MULTIBAND_ACQUISITION;
-import static android.hardware.gnss.IGnssPowerIndicationCallback.CAPABILITY_MULTIBAND_TRACKING;
-import static android.hardware.gnss.IGnssPowerIndicationCallback.CAPABILITY_OTHER_MODES;
-import static android.hardware.gnss.IGnssPowerIndicationCallback.CAPABILITY_SINGLEBAND_ACQUISITION;
-import static android.hardware.gnss.IGnssPowerIndicationCallback.CAPABILITY_SINGLEBAND_TRACKING;
-import static android.hardware.gnss.IGnssPowerIndicationCallback.CAPABILITY_TOTAL;
-
-import android.util.Log;
-
-import java.io.FileDescriptor;
-import java.io.PrintWriter;
-
-/**
- * Manages GNSS Power Indication operations.
- */
-class GnssPowerIndicationProvider {
- private static final String TAG = "GnssPowerIndPdr";
- private static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG);
- private volatile int mCapabilities;
- private GnssPowerStats mGnssPowerStats;
-
- /**
- * Handles GNSS Power Indication capabilities update from the GNSS HAL callback.
- */
- public void onCapabilitiesUpdated(int capabilities) {
- mCapabilities = capabilities;
- }
-
- public void onGnssPowerStatsAvailable(GnssPowerStats powerStats) {
- if (DEBUG) {
- Log.d(TAG, "onGnssPowerStatsAvailable: " + powerStats.toString());
- }
- powerStats.validate();
- mGnssPowerStats = powerStats;
- }
-
- /**
- * Returns the GNSS Power Indication specific capabilities.
- */
- public int getCapabilities() {
- return mCapabilities;
- }
-
- /**
- * Requests the GNSS HAL to report {@link GnssPowerStats}.
- */
- public static void requestPowerStats() {
- native_request_power_stats();
- }
-
- private boolean hasCapability(int capability) {
- return (mCapabilities & capability) != 0;
- }
-
- /**
- * Dump info for debugging.
- */
- public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
- if (mGnssPowerStats == null) {
- return;
- }
- pw.print("GnssPowerStats[");
- if (mGnssPowerStats.hasElapsedRealtimeNanos()) {
- pw.print("ElapsedRealtime=" + mGnssPowerStats.getElapsedRealtimeNanos());
- }
- if (mGnssPowerStats.hasElapsedRealtimeUncertaintyNanos()) {
- pw.print(", ElapsedRealtimeUncertaintyNanos="
- + mGnssPowerStats.getElapsedRealtimeUncertaintyNanos());
- }
- if (hasCapability(CAPABILITY_TOTAL)) {
- pw.print(", TotalEnergyMilliJoule=" + mGnssPowerStats.getTotalEnergyMilliJoule());
- }
- if (hasCapability(CAPABILITY_SINGLEBAND_TRACKING)) {
- pw.print(", SinglebandTrackingModeEnergyMilliJoule="
- + mGnssPowerStats.getSinglebandTrackingModeEnergyMilliJoule());
- }
- if (hasCapability(CAPABILITY_MULTIBAND_TRACKING)) {
- pw.print(", MultibandTrackingModeEnergyMilliJoule="
- + mGnssPowerStats.getMultibandTrackingModeEnergyMilliJoule());
- }
- if (hasCapability(CAPABILITY_SINGLEBAND_ACQUISITION)) {
- pw.print(", SinglebandAcquisitionModeEnergyMilliJoule="
- + mGnssPowerStats.getSinglebandAcquisitionModeEnergyMilliJoule());
- }
- if (hasCapability(CAPABILITY_MULTIBAND_ACQUISITION)) {
- pw.print(", MultibandAcquisitionModeEnergyMilliJoule="
- + mGnssPowerStats.getMultibandAcquisitionModeEnergyMilliJoule());
- }
- if (hasCapability(CAPABILITY_OTHER_MODES)) {
- pw.print(", OtherModesEnergyMilliJoule=[");
- double[] otherModes = mGnssPowerStats.getOtherModesEnergyMilliJoule();
- for (int i = 0; i < otherModes.length; i++) {
- pw.print(otherModes[i]);
- if (i < otherModes.length - 1) {
- pw.print(", ");
- }
- }
- pw.print("] ");
- }
- pw.println(']');
- }
-
- private static native void native_request_power_stats();
-}
diff --git a/services/core/java/com/android/server/location/gnss/GnssPowerStats.java b/services/core/java/com/android/server/location/gnss/GnssPowerStats.java
index b924d1f..924ffe1 100644
--- a/services/core/java/com/android/server/location/gnss/GnssPowerStats.java
+++ b/services/core/java/com/android/server/location/gnss/GnssPowerStats.java
@@ -19,13 +19,23 @@
import static android.hardware.gnss.ElapsedRealtime.HAS_TIMESTAMP_NS;
import static android.hardware.gnss.ElapsedRealtime.HAS_TIME_UNCERTAINTY_NS;
+import static java.util.concurrent.TimeUnit.NANOSECONDS;
+
+import android.location.GnssCapabilities;
+import android.util.IndentingPrintWriter;
+import android.util.TimeUtils;
+
import com.android.internal.util.Preconditions;
+import com.android.server.location.gnss.hal.GnssNative.GnssRealtimeFlags;
+
+import java.io.FileDescriptor;
/**
* Represents Cumulative GNSS power statistics since boot.
*/
-class GnssPowerStats {
- private final int mElapsedRealtimeFlags;
+public class GnssPowerStats {
+
+ private final @GnssRealtimeFlags int mElapsedRealtimeFlags;
private final long mElapsedRealtimeNanos;
private final double mElapsedRealtimeUncertaintyNanos;
private final double mTotalEnergyMilliJoule;
@@ -35,7 +45,7 @@
private final double mMultibandAcquisitionModeEnergyMilliJoule;
private final double[] mOtherModesEnergyMilliJoule;
- GnssPowerStats(int elapsedRealtimeFlags,
+ public GnssPowerStats(@GnssRealtimeFlags int elapsedRealtimeFlags,
long elapsedRealtimeNanos,
double elapsedRealtimeUncertaintyNanos,
double totalEnergyMilliJoule,
@@ -131,4 +141,51 @@
public void validate() {
Preconditions.checkArgument(hasElapsedRealtimeNanos());
}
+
+ /**
+ * Dumps power stat information filtered by the given capabilities.
+ */
+ public void dump(FileDescriptor fd, IndentingPrintWriter ipw, String[] args,
+ GnssCapabilities capabilities) {
+ if (hasElapsedRealtimeNanos()) {
+ ipw.print("time: ");
+ ipw.print(TimeUtils.formatRealtime(NANOSECONDS.toMillis(mElapsedRealtimeNanos)));
+ if (hasElapsedRealtimeUncertaintyNanos() && mElapsedRealtimeUncertaintyNanos != 0) {
+ ipw.print(" +/- ");
+ ipw.print(NANOSECONDS.toMillis((long) mElapsedRealtimeUncertaintyNanos));
+ }
+ }
+ if (capabilities.hasPowerTotal()) {
+ ipw.print("total power: ");
+ ipw.print(mTotalEnergyMilliJoule);
+ ipw.println("mJ");
+ }
+ if (capabilities.hasPowerSinglebandTracking()) {
+ ipw.print("single-band tracking power: ");
+ ipw.print(mSinglebandTrackingModeEnergyMilliJoule);
+ ipw.println("mJ");
+ }
+ if (capabilities.hasPowerMultibandTracking()) {
+ ipw.print("multi-band tracking power: ");
+ ipw.print(mMultibandTrackingModeEnergyMilliJoule);
+ ipw.println("mJ");
+ }
+ if (capabilities.hasPowerSinglebandAcquisition()) {
+ ipw.print("single-band acquisition power: ");
+ ipw.print(mSinglebandAcquisitionModeEnergyMilliJoule);
+ ipw.println("mJ");
+ }
+ if (capabilities.hasPowerMultibandAcquisition()) {
+ ipw.print("multi-band acquisition power: ");
+ ipw.print(mMultibandAcquisitionModeEnergyMilliJoule);
+ ipw.println("mJ");
+ }
+ if (capabilities.hasPowerOtherModes()) {
+ for (int i = 1; i <= mOtherModesEnergyMilliJoule.length; i++) {
+ ipw.print("other mode [" + i + "] power: ");
+ ipw.print(mOtherModesEnergyMilliJoule[i]);
+ ipw.println("mJ");
+ }
+ }
+ }
}
diff --git a/services/core/java/com/android/server/location/gnss/GnssStatusProvider.java b/services/core/java/com/android/server/location/gnss/GnssStatusProvider.java
index 49aa235..e0673db 100644
--- a/services/core/java/com/android/server/location/gnss/GnssStatusProvider.java
+++ b/services/core/java/com/android/server/location/gnss/GnssStatusProvider.java
@@ -20,6 +20,7 @@
import static com.android.server.location.gnss.GnssManagerService.TAG;
import android.app.AppOpsManager;
+import android.location.GnssCapabilities;
import android.location.GnssStatus;
import android.location.IGnssStatusListener;
import android.location.util.identity.CallerIdentity;
@@ -27,6 +28,7 @@
import android.stats.location.LocationStatsEnums;
import android.util.Log;
+import com.android.server.location.gnss.hal.GnssNative;
import com.android.server.location.injector.AppOpsHelper;
import com.android.server.location.injector.Injector;
import com.android.server.location.injector.LocationUsageLogger;
@@ -36,15 +38,23 @@
/**
* Implementation of a handler for {@link IGnssStatusListener}.
*/
-public class GnssStatusProvider extends GnssListenerMultiplexer<Void, IGnssStatusListener, Void> {
+public class GnssStatusProvider extends
+ GnssListenerMultiplexer<Void, IGnssStatusListener, Void> implements
+ GnssNative.BaseCallbacks, GnssNative.StatusCallbacks, GnssNative.SvStatusCallbacks {
private final AppOpsHelper mAppOpsHelper;
private final LocationUsageLogger mLogger;
- public GnssStatusProvider(Injector injector) {
+ private boolean mIsNavigating = false;
+
+ public GnssStatusProvider(Injector injector, GnssNative gnssNative) {
super(injector);
mAppOpsHelper = injector.getAppOpsHelper();
mLogger = injector.getLocationUsageLogger();
+
+ gnssNative.addBaseCallbacks(this);
+ gnssNative.addStatusCallbacks(this);
+ gnssNative.addSvStatusCallbacks(this);
}
@Override
@@ -95,30 +105,50 @@
registration.isForeground());
}
- /**
- * Called by GnssLocationProvider.
- */
- public void onStatusChanged(boolean isNavigating) {
- if (isNavigating) {
- deliverToListeners(IGnssStatusListener::onGnssStarted);
- } else {
- deliverToListeners(IGnssStatusListener::onGnssStopped);
+ @Override
+ public void onHalRestarted() {
+ resetService();
+ }
+
+ @Override
+ public void onCapabilitiesChanged(GnssCapabilities oldCapabilities,
+ GnssCapabilities newCapabilities) {}
+
+ @Override
+ public void onReportStatus(@GnssNative.StatusCallbacks.GnssStatusValue int gnssStatus) {
+ boolean isNavigating;
+ switch (gnssStatus) {
+ case GNSS_STATUS_SESSION_BEGIN:
+ isNavigating = true;
+ break;
+ case GNSS_STATUS_SESSION_END:
+ // fall through
+ case GNSS_STATUS_ENGINE_OFF:
+ isNavigating = false;
+ break;
+ default:
+ isNavigating = mIsNavigating;
+ }
+
+ if (isNavigating != mIsNavigating) {
+ mIsNavigating = isNavigating;
+ if (isNavigating) {
+ deliverToListeners(IGnssStatusListener::onGnssStarted);
+ } else {
+ deliverToListeners(IGnssStatusListener::onGnssStopped);
+ }
}
}
- /**
- * Called by GnssLocationProvider.
- */
- public void onFirstFix(int ttff) {
+ @Override
+ public void onReportFirstFix(int ttff) {
deliverToListeners(listener -> {
listener.onFirstFix(ttff);
});
}
- /**
- * Called by GnssLocationProvider.
- */
- public void onSvStatusChanged(GnssStatus gnssStatus) {
+ @Override
+ public void onReportSvStatus(GnssStatus gnssStatus) {
deliverToListeners(registration -> {
if (mAppOpsHelper.noteOpNoThrow(AppOpsManager.OP_FINE_LOCATION,
registration.getIdentity())) {
@@ -128,18 +158,4 @@
}
});
}
-
- /**
- * Called by GnssLocationProvider.
- */
- public void onNmeaReceived(long timestamp, String nmea) {
- deliverToListeners(registration -> {
- if (mAppOpsHelper.noteOpNoThrow(AppOpsManager.OP_FINE_LOCATION,
- registration.getIdentity())) {
- return listener -> listener.onNmeaReceived(timestamp, nmea);
- } else {
- return null;
- }
- });
- }
}
diff --git a/services/core/java/com/android/server/location/gnss/hal/GnssNative.java b/services/core/java/com/android/server/location/gnss/hal/GnssNative.java
new file mode 100644
index 0000000..89d8249
--- /dev/null
+++ b/services/core/java/com/android/server/location/gnss/hal/GnssNative.java
@@ -0,0 +1,1490 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.location.gnss.hal;
+
+import static com.android.server.location.gnss.GnssManagerService.TAG;
+
+import android.annotation.IntDef;
+import android.annotation.Nullable;
+import android.location.GnssAntennaInfo;
+import android.location.GnssCapabilities;
+import android.location.GnssMeasurementCorrections;
+import android.location.GnssMeasurementsEvent;
+import android.location.GnssNavigationMessage;
+import android.location.GnssStatus;
+import android.location.Location;
+import android.os.SystemClock;
+import android.util.Log;
+
+import com.android.internal.annotations.GuardedBy;
+import com.android.internal.annotations.VisibleForTesting;
+import com.android.internal.util.ArrayUtils;
+import com.android.internal.util.Preconditions;
+import com.android.server.FgThread;
+import com.android.server.location.gnss.GnssConfiguration;
+import com.android.server.location.gnss.GnssPowerStats;
+import com.android.server.location.injector.EmergencyHelper;
+import com.android.server.location.injector.Injector;
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+import java.util.List;
+import java.util.Objects;
+
+/**
+ * Entry point for most GNSS HAL commands and callbacks.
+ */
+public class GnssNative {
+
+ // IMPORTANT - must match GnssPositionMode enum in IGnss.hal
+ public static final int GNSS_POSITION_MODE_STANDALONE = 0;
+ public static final int GNSS_POSITION_MODE_MS_BASED = 1;
+ public static final int GNSS_POSITION_MODE_MS_ASSISTED = 2;
+
+ @IntDef(prefix = "GNSS_POSITION_MODE_", value = {GNSS_POSITION_MODE_STANDALONE,
+ GNSS_POSITION_MODE_MS_BASED, GNSS_POSITION_MODE_MS_ASSISTED})
+ @Retention(RetentionPolicy.SOURCE)
+ public @interface GnssPositionMode {}
+
+ // IMPORTANT - must match GnssPositionRecurrence enum in IGnss.hal
+ public static final int GNSS_POSITION_RECURRENCE_PERIODIC = 0;
+ public static final int GNSS_POSITION_RECURRENCE_SINGLE = 1;
+
+ @IntDef(prefix = "GNSS_POSITION_RECURRENCE_", value = {GNSS_POSITION_RECURRENCE_PERIODIC,
+ GNSS_POSITION_RECURRENCE_SINGLE})
+ @Retention(RetentionPolicy.SOURCE)
+ public @interface GnssPositionRecurrence {}
+
+ // IMPORTANT - must match the GnssLocationFlags enum in types.hal
+ public static final int GNSS_LOCATION_HAS_LAT_LONG = 1;
+ public static final int GNSS_LOCATION_HAS_ALTITUDE = 2;
+ public static final int GNSS_LOCATION_HAS_SPEED = 4;
+ public static final int GNSS_LOCATION_HAS_BEARING = 8;
+ public static final int GNSS_LOCATION_HAS_HORIZONTAL_ACCURACY = 16;
+ public static final int GNSS_LOCATION_HAS_VERTICAL_ACCURACY = 32;
+ public static final int GNSS_LOCATION_HAS_SPEED_ACCURACY = 64;
+ public static final int GNSS_LOCATION_HAS_BEARING_ACCURACY = 128;
+
+ @IntDef(flag = true, prefix = "GNSS_LOCATION_", value = {GNSS_LOCATION_HAS_LAT_LONG,
+ GNSS_LOCATION_HAS_ALTITUDE, GNSS_LOCATION_HAS_SPEED, GNSS_LOCATION_HAS_BEARING,
+ GNSS_LOCATION_HAS_HORIZONTAL_ACCURACY, GNSS_LOCATION_HAS_VERTICAL_ACCURACY,
+ GNSS_LOCATION_HAS_SPEED_ACCURACY, GNSS_LOCATION_HAS_BEARING_ACCURACY})
+ @Retention(RetentionPolicy.SOURCE)
+ public @interface GnssLocationFlags {}
+
+ // IMPORTANT - must match the ElapsedRealtimeFlags enum in types.hal
+ public static final int GNSS_REALTIME_HAS_TIMESTAMP_NS = 1;
+ public static final int GNSS_REALTIME_HAS_TIME_UNCERTAINTY_NS = 2;
+
+ @IntDef(flag = true, value = {GNSS_REALTIME_HAS_TIMESTAMP_NS,
+ GNSS_REALTIME_HAS_TIME_UNCERTAINTY_NS})
+ @Retention(RetentionPolicy.SOURCE)
+ public @interface GnssRealtimeFlags {}
+
+ // IMPORTANT - must match the GnssAidingData enum in IGnss.hal
+ public static final int GNSS_AIDING_TYPE_EPHEMERIS = 0x0001;
+ public static final int GNSS_AIDING_TYPE_ALMANAC = 0x0002;
+ public static final int GNSS_AIDING_TYPE_POSITION = 0x0004;
+ public static final int GNSS_AIDING_TYPE_TIME = 0x0008;
+ public static final int GNSS_AIDING_TYPE_IONO = 0x0010;
+ public static final int GNSS_AIDING_TYPE_UTC = 0x0020;
+ public static final int GNSS_AIDING_TYPE_HEALTH = 0x0040;
+ public static final int GNSS_AIDING_TYPE_SVDIR = 0x0080;
+ public static final int GNSS_AIDING_TYPE_SVSTEER = 0x0100;
+ public static final int GNSS_AIDING_TYPE_SADATA = 0x0200;
+ public static final int GNSS_AIDING_TYPE_RTI = 0x0400;
+ public static final int GNSS_AIDING_TYPE_CELLDB_INFO = 0x8000;
+ public static final int GNSS_AIDING_TYPE_ALL = 0xFFFF;
+
+ @IntDef(flag = true, prefix = "GNSS_AIDING_", value = {GNSS_AIDING_TYPE_EPHEMERIS,
+ GNSS_AIDING_TYPE_ALMANAC, GNSS_AIDING_TYPE_POSITION, GNSS_AIDING_TYPE_TIME,
+ GNSS_AIDING_TYPE_IONO, GNSS_AIDING_TYPE_UTC, GNSS_AIDING_TYPE_HEALTH,
+ GNSS_AIDING_TYPE_SVDIR, GNSS_AIDING_TYPE_SVSTEER, GNSS_AIDING_TYPE_SADATA,
+ GNSS_AIDING_TYPE_RTI, GNSS_AIDING_TYPE_CELLDB_INFO, GNSS_AIDING_TYPE_ALL})
+ @Retention(RetentionPolicy.SOURCE)
+ public @interface GnssAidingTypeFlags {}
+
+ // IMPORTANT - must match OEM definitions, this isn't part of a hal for some reason
+ public static final int AGPS_REF_LOCATION_TYPE_GSM_CELLID = 1;
+ public static final int AGPS_REF_LOCATION_TYPE_UMTS_CELLID = 2;
+
+ @IntDef(prefix = "AGPS_REF_LOCATION_TYPE_", value = {AGPS_REF_LOCATION_TYPE_GSM_CELLID,
+ AGPS_REF_LOCATION_TYPE_UMTS_CELLID})
+ @Retention(RetentionPolicy.SOURCE)
+ public @interface AgpsReferenceLocationType {}
+
+ // IMPORTANT - must match OEM definitions, this isn't part of a hal for some reason
+ public static final int AGPS_SETID_TYPE_NONE = 0;
+ public static final int AGPS_SETID_TYPE_IMSI = 1;
+ public static final int AGPS_SETID_TYPE_MSISDN = 2;
+
+ @IntDef(prefix = "AGPS_SETID_TYPE_", value = {AGPS_SETID_TYPE_NONE, AGPS_SETID_TYPE_IMSI,
+ AGPS_SETID_TYPE_MSISDN})
+ @Retention(RetentionPolicy.SOURCE)
+ public @interface AgpsSetIdType {}
+
+ /** Callbacks relevant to the entire HAL. */
+ public interface BaseCallbacks {
+ void onHalRestarted();
+ void onCapabilitiesChanged(GnssCapabilities oldCapabilities,
+ GnssCapabilities newCapabilities);
+ }
+
+ /** Callbacks for status events. */
+ public interface StatusCallbacks {
+
+ // IMPORTANT - must match GnssStatusValue enum in IGnssCallback.hal
+ int GNSS_STATUS_NONE = 0;
+ int GNSS_STATUS_SESSION_BEGIN = 1;
+ int GNSS_STATUS_SESSION_END = 2;
+ int GNSS_STATUS_ENGINE_ON = 3;
+ int GNSS_STATUS_ENGINE_OFF = 4;
+
+ @IntDef(prefix = "GNSS_STATUS_", value = {GNSS_STATUS_NONE, GNSS_STATUS_SESSION_BEGIN,
+ GNSS_STATUS_SESSION_END, GNSS_STATUS_ENGINE_ON, GNSS_STATUS_ENGINE_OFF})
+ @Retention(RetentionPolicy.SOURCE)
+ @interface GnssStatusValue {}
+
+ void onReportStatus(@GnssStatusValue int status);
+ void onReportFirstFix(int ttff);
+ }
+
+ /** Callbacks for SV status events. */
+ public interface SvStatusCallbacks {
+ void onReportSvStatus(GnssStatus gnssStatus);
+ }
+
+ /** Callbacks for NMEA events. */
+ public interface NmeaCallbacks {
+ void onReportNmea(long timestamp);
+ }
+
+ /** Callbacks for location events. */
+ public interface LocationCallbacks {
+ void onReportLocation(boolean hasLatLong, Location location);
+ void onReportLocations(Location[] locations);
+ }
+
+ /** Callbacks for measurement events. */
+ public interface MeasurementCallbacks {
+ void onReportMeasurements(GnssMeasurementsEvent event);
+ }
+
+ /** Callbacks for antenna info events. */
+ public interface AntennaInfoCallbacks {
+ void onReportAntennaInfo(List<GnssAntennaInfo> antennaInfos);
+ }
+
+ /** Callbacks for navigation message events. */
+ public interface NavigationMessageCallbacks {
+ void onReportNavigationMessage(GnssNavigationMessage event);
+ }
+
+ /** Callbacks for geofence events. */
+ public interface GeofenceCallbacks {
+
+ // IMPORTANT - must match GeofenceTransition enum in IGnssGeofenceCallback.hal
+ int GEOFENCE_TRANSITION_ENTERED = 1 << 0L;
+ int GEOFENCE_TRANSITION_EXITED = 1 << 1L;
+ int GEOFENCE_TRANSITION_UNCERTAIN = 1 << 2L;
+
+ @IntDef(prefix = "GEOFENCE_TRANSITION_", value = {GEOFENCE_TRANSITION_ENTERED,
+ GEOFENCE_TRANSITION_EXITED, GEOFENCE_TRANSITION_UNCERTAIN})
+ @Retention(RetentionPolicy.SOURCE)
+ @interface GeofenceTransition {}
+
+ // IMPORTANT - must match GeofenceAvailability enum in IGnssGeofenceCallback.hal
+ int GEOFENCE_AVAILABILITY_UNAVAILABLE = 1 << 0L;
+ int GEOFENCE_AVAILABILITY_AVAILABLE = 1 << 1L;
+
+ @IntDef(prefix = "GEOFENCE_AVAILABILITY_", value = {GEOFENCE_AVAILABILITY_UNAVAILABLE,
+ GEOFENCE_AVAILABILITY_AVAILABLE})
+ @Retention(RetentionPolicy.SOURCE)
+ @interface GeofenceAvailability {}
+
+ // IMPORTANT - must match GeofenceStatus enum in IGnssGeofenceCallback.hal
+ int GEOFENCE_STATUS_OPERATION_SUCCESS = 0;
+ int GEOFENCE_STATUS_ERROR_TOO_MANY_GEOFENCES = 100;
+ int GEOFENCE_STATUS_ERROR_ID_EXISTS = -101;
+ int GEOFENCE_STATUS_ERROR_ID_UNKNOWN = -102;
+ int GEOFENCE_STATUS_ERROR_INVALID_TRANSITION = -103;
+ int GEOFENCE_STATUS_ERROR_GENERIC = -149;
+
+ @IntDef(prefix = "GEOFENCE_STATUS_", value = {GEOFENCE_STATUS_OPERATION_SUCCESS,
+ GEOFENCE_STATUS_ERROR_TOO_MANY_GEOFENCES, GEOFENCE_STATUS_ERROR_ID_EXISTS,
+ GEOFENCE_STATUS_ERROR_ID_UNKNOWN, GEOFENCE_STATUS_ERROR_INVALID_TRANSITION,
+ GEOFENCE_STATUS_ERROR_GENERIC})
+ @Retention(RetentionPolicy.SOURCE)
+ @interface GeofenceStatus {}
+
+ void onReportGeofenceTransition(int geofenceId, Location location,
+ @GeofenceTransition int transition, long timestamp);
+ void onReportGeofenceStatus(@GeofenceAvailability int availabilityStatus,
+ Location location);
+ void onReportGeofenceAddStatus(int geofenceId, @GeofenceStatus int status);
+ void onReportGeofenceRemoveStatus(int geofenceId, @GeofenceStatus int status);
+ void onReportGeofencePauseStatus(int geofenceId, @GeofenceStatus int status);
+ void onReportGeofenceResumeStatus(int geofenceId, @GeofenceStatus int status);
+ }
+
+ /** Callbacks for the HAL requesting time. */
+ public interface TimeCallbacks {
+ void onRequestUtcTime();
+ }
+
+ /** Callbacks for the HAL requesting locations. */
+ public interface LocationRequestCallbacks {
+ void onRequestLocation(boolean independentFromGnss, boolean isUserEmergency);
+ void onRequestRefLocation();
+ }
+
+ /** Callbacks for HAL requesting PSDS download. */
+ public interface PsdsCallbacks {
+ void onRequestPsdsDownload(int psdsType);
+ }
+
+ /** Callbacks for AGPS functionality. */
+ public interface AGpsCallbacks {
+
+ // IMPORTANT - must match OEM definitions, this isn't part of a hal for some reason
+ int AGPS_REQUEST_SETID_IMSI = 1 << 0L;
+ int AGPS_REQUEST_SETID_MSISDN = 1 << 1L;
+
+ @IntDef(flag = true, prefix = "AGPS_REQUEST_SETID_", value = {AGPS_REQUEST_SETID_IMSI,
+ AGPS_REQUEST_SETID_MSISDN})
+ @Retention(RetentionPolicy.SOURCE)
+ @interface AgpsSetIdFlags {}
+
+ void onReportAGpsStatus(int agpsType, int agpsStatus, byte[] suplIpAddr);
+ void onRequestSetID(@AgpsSetIdFlags int flags);
+ }
+
+ /** Callbacks for notifications. */
+ public interface NotificationCallbacks {
+ void onReportNiNotification(int notificationId, int niType, int notifyFlags,
+ int timeout, int defaultResponse, String requestorId, String text,
+ int requestorIdEncoding, int textEncoding);
+ void onReportNfwNotification(String proxyAppPackageName, byte protocolStack,
+ String otherProtocolStackName, byte requestor, String requestorId,
+ byte responseType, boolean inEmergencyMode, boolean isCachedLocation);
+ }
+
+ // set lower than the current ITAR limit of 600m/s to allow this to trigger even if GPS HAL
+ // stops output right at 600m/s, depriving this of the information of a device that reaches
+ // greater than 600m/s, and higher than the speed of sound to avoid impacting most use cases.
+ private static final float ITAR_SPEED_LIMIT_METERS_PER_SECOND = 400.0f;
+
+ /**
+ * 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 {}
+
+ @GuardedBy("GnssNative.class")
+ private static GnssHal sGnssHal;
+
+ @GuardedBy("GnssNative.class")
+ private static boolean sGnssHalInitialized;
+
+ @GuardedBy("GnssNative.class")
+ private static GnssNative sInstance;
+
+ /**
+ * Sets GnssHal instance to use for testing.
+ */
+ @VisibleForTesting
+ public static synchronized void setGnssHalForTest(GnssHal gnssHal) {
+ sGnssHal = Objects.requireNonNull(gnssHal);
+ sGnssHalInitialized = false;
+ sInstance = null;
+ }
+
+ private static synchronized void initializeHal() {
+ if (!sGnssHalInitialized) {
+ if (sGnssHal == null) {
+ sGnssHal = new GnssHal();
+ }
+ sGnssHal.classInitOnce();
+ sGnssHalInitialized = true;
+ }
+ }
+
+ /**
+ * Returns true if GNSS is supported on this device. If true, then
+ * {@link #create(Injector, GnssConfiguration)} may be invoked.
+ */
+ public static synchronized boolean isSupported() {
+ initializeHal();
+ return sGnssHal.isSupported();
+ }
+
+ /**
+ * Creates a new instance of GnssNative. Should only be invoked if {@link #isSupported()} is
+ * true. May only be invoked once.
+ */
+ public static synchronized GnssNative create(Injector injector,
+ GnssConfiguration configuration) {
+ // side effect - ensures initialization
+ Preconditions.checkState(isSupported());
+ Preconditions.checkState(sInstance == null);
+ return (sInstance = new GnssNative(sGnssHal, injector, configuration));
+ }
+
+ private final GnssHal mGnssHal;
+ private final EmergencyHelper mEmergencyHelper;
+ private final GnssConfiguration mConfiguration;
+
+ // these callbacks may have multiple implementations
+ private BaseCallbacks[] mBaseCallbacks = new BaseCallbacks[0];
+ private StatusCallbacks[] mStatusCallbacks = new StatusCallbacks[0];
+ private SvStatusCallbacks[] mSvStatusCallbacks = new SvStatusCallbacks[0];
+ private NmeaCallbacks[] mNmeaCallbacks = new NmeaCallbacks[0];
+ private LocationCallbacks[] mLocationCallbacks = new LocationCallbacks[0];
+ private MeasurementCallbacks[] mMeasurementCallbacks = new MeasurementCallbacks[0];
+ private AntennaInfoCallbacks[] mAntennaInfoCallbacks = new AntennaInfoCallbacks[0];
+ private NavigationMessageCallbacks[] mNavigationMessageCallbacks =
+ new NavigationMessageCallbacks[0];
+
+ // these callbacks may only have a single implementation
+ private GeofenceCallbacks mGeofenceCallbacks;
+ private TimeCallbacks mTimeCallbacks;
+ private LocationRequestCallbacks mLocationRequestCallbacks;
+ private PsdsCallbacks mPsdsCallbacks;
+ private AGpsCallbacks mAGpsCallbacks;
+ private NotificationCallbacks mNotificationCallbacks;
+
+ private boolean mRegistered;
+
+ private volatile boolean mItarSpeedLimitExceeded;
+
+ private GnssCapabilities mCapabilities = new GnssCapabilities.Builder().build();
+ private @Nullable GnssPowerStats mPowerStats = null;
+ private int mHardwareYear = 0;
+ private @Nullable String mHardwareModelName = null;
+ private long mStartRealtimeMs = 0;
+ private boolean mHasFirstFix = false;
+
+ private GnssNative(GnssHal gnssHal, Injector injector, GnssConfiguration configuration) {
+ mGnssHal = Objects.requireNonNull(gnssHal);
+ mEmergencyHelper = injector.getEmergencyHelper();
+ mConfiguration = configuration;
+ }
+
+ public void addBaseCallbacks(BaseCallbacks callbacks) {
+ Preconditions.checkState(!mRegistered);
+ mBaseCallbacks = ArrayUtils.appendElement(BaseCallbacks.class, mBaseCallbacks, callbacks);
+ }
+
+ public void addStatusCallbacks(StatusCallbacks callbacks) {
+ Preconditions.checkState(!mRegistered);
+ mStatusCallbacks = ArrayUtils.appendElement(StatusCallbacks.class, mStatusCallbacks,
+ callbacks);
+ }
+
+ public void addSvStatusCallbacks(SvStatusCallbacks callbacks) {
+ Preconditions.checkState(!mRegistered);
+ mSvStatusCallbacks = ArrayUtils.appendElement(SvStatusCallbacks.class, mSvStatusCallbacks,
+ callbacks);
+ }
+
+ public void addNmeaCallbacks(NmeaCallbacks callbacks) {
+ Preconditions.checkState(!mRegistered);
+ mNmeaCallbacks = ArrayUtils.appendElement(NmeaCallbacks.class, mNmeaCallbacks,
+ callbacks);
+ }
+
+ public void addLocationCallbacks(LocationCallbacks callbacks) {
+ Preconditions.checkState(!mRegistered);
+ mLocationCallbacks = ArrayUtils.appendElement(LocationCallbacks.class, mLocationCallbacks,
+ callbacks);
+ }
+
+ public void addMeasurementCallbacks(MeasurementCallbacks callbacks) {
+ Preconditions.checkState(!mRegistered);
+ mMeasurementCallbacks = ArrayUtils.appendElement(MeasurementCallbacks.class,
+ mMeasurementCallbacks, callbacks);
+ }
+
+ public void addAntennaInfoCallbacks(AntennaInfoCallbacks callbacks) {
+ Preconditions.checkState(!mRegistered);
+ mAntennaInfoCallbacks = ArrayUtils.appendElement(AntennaInfoCallbacks.class,
+ mAntennaInfoCallbacks, callbacks);
+ }
+
+ public void addNavigationMessageCallbacks(NavigationMessageCallbacks callbacks) {
+ Preconditions.checkState(!mRegistered);
+ mNavigationMessageCallbacks = ArrayUtils.appendElement(NavigationMessageCallbacks.class,
+ mNavigationMessageCallbacks, callbacks);
+ }
+
+ public void setGeofenceCallbacks(GeofenceCallbacks callbacks) {
+ Preconditions.checkState(!mRegistered);
+ Preconditions.checkState(mGeofenceCallbacks == null);
+ mGeofenceCallbacks = Objects.requireNonNull(callbacks);
+ }
+
+ public void setTimeCallbacks(TimeCallbacks callbacks) {
+ Preconditions.checkState(!mRegistered);
+ Preconditions.checkState(mTimeCallbacks == null);
+ mTimeCallbacks = Objects.requireNonNull(callbacks);
+ }
+
+ public void setLocationRequestCallbacks(LocationRequestCallbacks callbacks) {
+ Preconditions.checkState(!mRegistered);
+ Preconditions.checkState(mLocationRequestCallbacks == null);
+ mLocationRequestCallbacks = Objects.requireNonNull(callbacks);
+ }
+
+ public void setPsdsCallbacks(PsdsCallbacks callbacks) {
+ Preconditions.checkState(!mRegistered);
+ Preconditions.checkState(mPsdsCallbacks == null);
+ mPsdsCallbacks = Objects.requireNonNull(callbacks);
+ }
+
+ public void setAGpsCallbacks(AGpsCallbacks callbacks) {
+ Preconditions.checkState(!mRegistered);
+ Preconditions.checkState(mAGpsCallbacks == null);
+ mAGpsCallbacks = Objects.requireNonNull(callbacks);
+ }
+
+ public void setNotificationCallbacks(NotificationCallbacks callbacks) {
+ Preconditions.checkState(!mRegistered);
+ Preconditions.checkState(mNotificationCallbacks == null);
+ mNotificationCallbacks = Objects.requireNonNull(callbacks);
+ }
+
+ /**
+ * Registers with the HAL and allows callbacks to begin. Once registered with the native HAL,
+ * no more callbacks can be added or set. Must only be called once.
+ */
+ public void register() {
+ Preconditions.checkState(!mRegistered);
+ mRegistered = true;
+
+ initializeGnss(false);
+ }
+
+ private void initializeGnss(boolean restart) {
+ Preconditions.checkState(mRegistered);
+ mGnssHal.initOnce(GnssNative.this, restart);
+
+ // gnss chipset appears to require an init/cleanup cycle on startup in order to properly
+ // initialize - undocumented and no idea why this is the case
+ if (mGnssHal.init()) {
+ mGnssHal.cleanup();
+ Log.i(TAG, "gnss hal initialized");
+ } else {
+ Log.e(TAG, "gnss hal initialization failed");
+ }
+ }
+
+ public GnssConfiguration getConfiguration() {
+ return mConfiguration;
+ }
+
+ /**
+ * Starts up GNSS HAL, and has undocumented side effect of informing HAL that location is
+ * allowed by settings.
+ */
+ public boolean init() {
+ Preconditions.checkState(mRegistered);
+ return mGnssHal.init();
+ }
+
+ /**
+ * Shuts down GNSS HAL, and has undocumented side effect of informing HAL that location is not
+ * allowed by settings.
+ */
+ public void cleanup() {
+ Preconditions.checkState(mRegistered);
+ mGnssHal.cleanup();
+ }
+
+ /**
+ * Returns the latest power stats from the GNSS HAL.
+ */
+ public @Nullable GnssPowerStats getPowerStats() {
+ return mPowerStats;
+ }
+
+ /**
+ * Returns current capabilities of the GNSS HAL.
+ */
+ public GnssCapabilities getCapabilities() {
+ return mCapabilities;
+ }
+
+ /**
+ * Returns hardware year of GNSS chipset.
+ */
+ public int getHardwareYear() {
+ return mHardwareYear;
+ }
+
+ /**
+ * Returns hardware model name of GNSS chipset.
+ */
+ public @Nullable String getHardwareModelName() {
+ return mHardwareModelName;
+ }
+
+ /**
+ * Returns true if the ITAR speed limit is currently being exceeded, and thus location
+ * information may be blocked.
+ */
+ public boolean isItarSpeedLimitExceeded() {
+ return mItarSpeedLimitExceeded;
+ }
+
+ /**
+ * Starts the GNSS HAL.
+ */
+ public boolean start() {
+ Preconditions.checkState(mRegistered);
+ mStartRealtimeMs = SystemClock.elapsedRealtime();
+ mHasFirstFix = false;
+ return mGnssHal.start();
+ }
+
+ /**
+ * Stops the GNSS HAL.
+ */
+ public boolean stop() {
+ Preconditions.checkState(mRegistered);
+ return mGnssHal.stop();
+ }
+
+ /**
+ * Sets the position mode.
+ */
+ public boolean setPositionMode(@GnssPositionMode int mode,
+ @GnssPositionRecurrence int recurrence, int minInterval, int preferredAccuracy,
+ int preferredTime, boolean lowPowerMode) {
+ Preconditions.checkState(mRegistered);
+ return mGnssHal.setPositionMode(mode, recurrence, minInterval, preferredAccuracy,
+ preferredTime, lowPowerMode);
+ }
+
+ /**
+ * Returns a debug string from the GNSS HAL.
+ */
+ public String getInternalState() {
+ Preconditions.checkState(mRegistered);
+ return mGnssHal.getInternalState();
+ }
+
+ /**
+ * Deletes any aiding data specified by the given flags.
+ */
+ public void deleteAidingData(@GnssAidingTypeFlags int flags) {
+ Preconditions.checkState(mRegistered);
+ mGnssHal.deleteAidingData(flags);
+ }
+
+ /**
+ * Reads an NMEA message into the given buffer, returning the number of bytes loaded into the
+ * buffer.
+ */
+ public int readNmea(byte[] buffer, int bufferSize) {
+ Preconditions.checkState(mRegistered);
+ return mGnssHal.readNmea(buffer, bufferSize);
+ }
+
+ /**
+ * Injects location information into the GNSS HAL.
+ */
+ public void injectLocation(Location location) {
+ Preconditions.checkState(mRegistered);
+ if (location.hasAccuracy()) {
+ mGnssHal.injectLocation(location.getLatitude(), location.getLongitude(),
+ location.getAccuracy());
+ }
+ }
+
+ /**
+ * Injects a location into the GNSS HAL in response to a HAL request for location.
+ */
+ public void injectBestLocation(Location location) {
+ Preconditions.checkState(mRegistered);
+
+ int gnssLocationFlags = GNSS_LOCATION_HAS_LAT_LONG
+ | (location.hasAltitude() ? GNSS_LOCATION_HAS_ALTITUDE : 0)
+ | (location.hasSpeed() ? GNSS_LOCATION_HAS_SPEED : 0)
+ | (location.hasBearing() ? GNSS_LOCATION_HAS_BEARING : 0)
+ | (location.hasAccuracy() ? GNSS_LOCATION_HAS_HORIZONTAL_ACCURACY : 0)
+ | (location.hasVerticalAccuracy() ? GNSS_LOCATION_HAS_VERTICAL_ACCURACY : 0)
+ | (location.hasSpeedAccuracy() ? GNSS_LOCATION_HAS_SPEED_ACCURACY : 0)
+ | (location.hasBearingAccuracy() ? GNSS_LOCATION_HAS_BEARING_ACCURACY : 0);
+
+ double latitudeDegrees = location.getLatitude();
+ double longitudeDegrees = location.getLongitude();
+ double altitudeMeters = location.getAltitude();
+ float speedMetersPerSec = location.getSpeed();
+ float bearingDegrees = location.getBearing();
+ float horizontalAccuracyMeters = location.getAccuracy();
+ float verticalAccuracyMeters = location.getVerticalAccuracyMeters();
+ float speedAccuracyMetersPerSecond = location.getSpeedAccuracyMetersPerSecond();
+ float bearingAccuracyDegrees = location.getBearingAccuracyDegrees();
+ long timestamp = location.getTime();
+
+ int elapsedRealtimeFlags = GNSS_REALTIME_HAS_TIMESTAMP_NS
+ | (location.hasElapsedRealtimeUncertaintyNanos()
+ ? GNSS_REALTIME_HAS_TIME_UNCERTAINTY_NS : 0);
+ long elapsedRealtimeNanos = location.getElapsedRealtimeNanos();
+ double elapsedRealtimeUncertaintyNanos = location.getElapsedRealtimeUncertaintyNanos();
+
+ mGnssHal.injectBestLocation(gnssLocationFlags, latitudeDegrees, longitudeDegrees,
+ altitudeMeters, speedMetersPerSec, bearingDegrees, horizontalAccuracyMeters,
+ verticalAccuracyMeters, speedAccuracyMetersPerSecond, bearingAccuracyDegrees,
+ timestamp, elapsedRealtimeFlags, elapsedRealtimeNanos,
+ elapsedRealtimeUncertaintyNanos);
+ }
+
+ /**
+ * Injects time information into the GNSS HAL.
+ */
+ public void injectTime(long time, long timeReference, int uncertainty) {
+ Preconditions.checkState(mRegistered);
+ mGnssHal.injectTime(time, timeReference, uncertainty);
+ }
+
+ /**
+ * Returns true if navigation message collection is supported.
+ */
+ public boolean isNavigationMessageCollectionSupported() {
+ Preconditions.checkState(mRegistered);
+ return mGnssHal.isNavigationMessageCollectionSupported();
+ }
+
+ /**
+ * Starts navigation message collection.
+ */
+ public boolean startNavigationMessageCollection() {
+ Preconditions.checkState(mRegistered);
+ return mGnssHal.startNavigationMessageCollection();
+ }
+
+ /**
+ * Stops navigation message collection.
+ */
+ public boolean stopNavigationMessageCollection() {
+ Preconditions.checkState(mRegistered);
+ return mGnssHal.stopNavigationMessageCollection();
+ }
+
+ /**
+ * Returns true if antenna info listening is supported.
+ */
+ public boolean isAntennaInfoListeningSupported() {
+ Preconditions.checkState(mRegistered);
+ return mGnssHal.isAntennaInfoListeningSupported();
+ }
+
+ /**
+ * Starts antenna info listening.
+ */
+ public boolean startAntennaInfoListening() {
+ Preconditions.checkState(mRegistered);
+ return mGnssHal.startAntennaInfoListening();
+ }
+
+ /**
+ * Stops antenna info listening.
+ */
+ public boolean stopAntennaInfoListening() {
+ Preconditions.checkState(mRegistered);
+ return mGnssHal.stopAntennaInfoListening();
+ }
+
+ /**
+ * Returns true if measurement collection is supported.
+ */
+ public boolean isMeasurementSupported() {
+ Preconditions.checkState(mRegistered);
+ return mGnssHal.isMeasurementSupported();
+ }
+
+ /**
+ * Starts measurement collection.
+ */
+ public boolean startMeasurementCollection(boolean enableFullTracking) {
+ Preconditions.checkState(mRegistered);
+ return mGnssHal.startMeasurementCollection(enableFullTracking);
+ }
+
+ /**
+ * Stops measurement collection.
+ */
+ public boolean stopMeasurementCollection() {
+ Preconditions.checkState(mRegistered);
+ return mGnssHal.stopMeasurementCollection();
+ }
+
+ /**
+ * Returns true if measurement corrections are supported.
+ */
+ public boolean isMeasurementCorrectionsSupported() {
+ Preconditions.checkState(mRegistered);
+ return mGnssHal.isMeasurementCorrectionsSupported();
+ }
+
+ /**
+ * Injects measurement corrections into the GNSS HAL.
+ */
+ public boolean injectMeasurementCorrections(GnssMeasurementCorrections corrections) {
+ Preconditions.checkState(mRegistered);
+ return mGnssHal.injectMeasurementCorrections(corrections);
+ }
+
+ /**
+ * Initialize batching.
+ */
+ public boolean initBatching() {
+ Preconditions.checkState(mRegistered);
+ return mGnssHal.initBatching();
+ }
+
+ /**
+ * Cleanup batching.
+ */
+ public void cleanupBatching() {
+ Preconditions.checkState(mRegistered);
+ mGnssHal.cleanupBatching();
+ }
+
+ /**
+ * Start batching.
+ */
+ public boolean startBatch(long periodNanos, boolean wakeOnFifoFull) {
+ Preconditions.checkState(mRegistered);
+ return mGnssHal.startBatch(periodNanos, wakeOnFifoFull);
+ }
+
+ /**
+ * Flush batching.
+ */
+ public void flushBatch() {
+ Preconditions.checkState(mRegistered);
+ mGnssHal.flushBatch();
+ }
+
+ /**
+ * Stop batching.
+ */
+ public void stopBatch() {
+ Preconditions.checkState(mRegistered);
+ mGnssHal.stopBatch();
+ }
+
+ /**
+ * Get current batching size.
+ */
+ public int getBatchSize() {
+ Preconditions.checkState(mRegistered);
+ return mGnssHal.getBatchSize();
+ }
+
+ /**
+ * Check if GNSS geofencing is supported.
+ */
+ public boolean isGeofencingSupported() {
+ Preconditions.checkState(mRegistered);
+ return mGnssHal.isGeofencingSupported();
+ }
+
+ /**
+ * Add geofence.
+ */
+ public boolean addGeofence(int geofenceId, double latitude, double longitude, double radius,
+ int lastTransition, int monitorTransitions, int notificationResponsiveness,
+ int unknownTimer) {
+ Preconditions.checkState(mRegistered);
+ return mGnssHal.addGeofence(geofenceId, latitude, longitude, radius, lastTransition,
+ monitorTransitions, notificationResponsiveness, unknownTimer);
+ }
+
+ /**
+ * Resume geofence.
+ */
+ public boolean resumeGeofence(int geofenceId, int monitorTransitions) {
+ Preconditions.checkState(mRegistered);
+ return mGnssHal.resumeGeofence(geofenceId, monitorTransitions);
+ }
+
+ /**
+ * Pause geofence.
+ */
+ public boolean pauseGeofence(int geofenceId) {
+ Preconditions.checkState(mRegistered);
+ return mGnssHal.pauseGeofence(geofenceId);
+ }
+
+ /**
+ * Remove geofence.
+ */
+ public boolean removeGeofence(int geofenceId) {
+ Preconditions.checkState(mRegistered);
+ return mGnssHal.removeGeofence(geofenceId);
+ }
+
+ /**
+ * Returns true if visibility control is supported.
+ */
+ public boolean isGnssVisibilityControlSupported() {
+ Preconditions.checkState(mRegistered);
+ return mGnssHal.isGnssVisibilityControlSupported();
+ }
+
+ /**
+ * Send a network initiated respnse.
+ */
+ public void sendNiResponse(int notificationId, int userResponse) {
+ Preconditions.checkState(mRegistered);
+ mGnssHal.sendNiResponse(notificationId, userResponse);
+ }
+
+ /**
+ * Request an eventual update of GNSS power statistics.
+ */
+ public void requestPowerStats() {
+ Preconditions.checkState(mRegistered);
+ mGnssHal.requestPowerStats();
+ }
+
+ /**
+ * Sets AGPS server information.
+ */
+ public void setAgpsServer(int type, String hostname, int port) {
+ Preconditions.checkState(mRegistered);
+ mGnssHal.setAgpsServer(type, hostname, port);
+ }
+
+ /**
+ * Sets AGPS set id.
+ */
+ public void setAgpsSetId(@AgpsSetIdType int type, String setId) {
+ Preconditions.checkState(mRegistered);
+ mGnssHal.setAgpsSetId(type, setId);
+ }
+
+ /**
+ * Sets AGPS reference cell id location.
+ */
+ public void setAgpsReferenceLocationCellId(@AgpsReferenceLocationType int type, int mcc,
+ int mnc, int lac, int cid) {
+ Preconditions.checkState(mRegistered);
+ mGnssHal.setAgpsReferenceLocationCellId(type, mcc, mnc, lac, cid);
+ }
+
+ /**
+ * Returns true if Predicted Satellite Data Service APIs are supported.
+ */
+ public boolean isPsdsSupported() {
+ Preconditions.checkState(mRegistered);
+ return mGnssHal.isPsdsSupported();
+ }
+
+ /**
+ * Injects Predicited Satellite Data Service data into the GNSS HAL.
+ */
+ public void injectPsdsData(byte[] data, int length, int psdsType) {
+ Preconditions.checkState(mRegistered);
+ mGnssHal.injectPsdsData(data, length, psdsType);
+ }
+
+ @NativeEntryPoint
+ void reportGnssServiceDied() {
+ Log.e(TAG, "gnss hal died - restarting shortly...");
+
+ // move to another thread just in case there is some awkward gnss thread dependency with
+ // the death notification. there shouldn't be, but you never know with gnss...
+ FgThread.getExecutor().execute(this::restartHal);
+ }
+
+ @VisibleForTesting
+ void restartHal() {
+ initializeGnss(true);
+ Log.e(TAG, "gnss hal restarted");
+
+ for (int i = 0; i < mBaseCallbacks.length; i++) {
+ mBaseCallbacks[i].onHalRestarted();
+ }
+ }
+
+ @NativeEntryPoint
+ void reportLocation(boolean hasLatLong, Location location) {
+ if (hasLatLong && !mHasFirstFix) {
+ mHasFirstFix = true;
+
+ // notify status listeners
+ int ttff = (int) (SystemClock.elapsedRealtime() - mStartRealtimeMs);
+ for (int i = 0; i < mStatusCallbacks.length; i++) {
+ mStatusCallbacks[i].onReportFirstFix(ttff);
+ }
+ }
+
+ if (location.hasSpeed()) {
+ boolean exceeded = location.getSpeed() > ITAR_SPEED_LIMIT_METERS_PER_SECOND;
+ if (!mItarSpeedLimitExceeded && exceeded) {
+ Log.w(TAG, "speed nearing ITAR threshold - blocking further GNSS output");
+ } else if (mItarSpeedLimitExceeded && !exceeded) {
+ Log.w(TAG, "speed leaving ITAR threshold - allowing further GNSS output");
+ }
+ mItarSpeedLimitExceeded = exceeded;
+ }
+
+ if (mItarSpeedLimitExceeded) {
+ return;
+ }
+
+ for (int i = 0; i < mLocationCallbacks.length; i++) {
+ mLocationCallbacks[i].onReportLocation(hasLatLong, location);
+ }
+ }
+
+ @NativeEntryPoint
+ void reportStatus(@StatusCallbacks.GnssStatusValue int gnssStatus) {
+ for (int i = 0; i < mStatusCallbacks.length; i++) {
+ mStatusCallbacks[i].onReportStatus(gnssStatus);
+ }
+ }
+
+ @NativeEntryPoint
+ void reportSvStatus(int svCount, int[] svidWithFlags, float[] cn0DbHzs,
+ float[] elevations, float[] azimuths, float[] carrierFrequencies,
+ float[] basebandCn0DbHzs) {
+ GnssStatus gnssStatus = GnssStatus.wrap(svCount, svidWithFlags, cn0DbHzs, elevations,
+ azimuths, carrierFrequencies, basebandCn0DbHzs);
+ for (int i = 0; i < mSvStatusCallbacks.length; i++) {
+ mSvStatusCallbacks[i].onReportSvStatus(gnssStatus);
+ }
+ }
+
+ @NativeEntryPoint
+ void reportAGpsStatus(int agpsType, int agpsStatus, byte[] suplIpAddr) {
+ mAGpsCallbacks.onReportAGpsStatus(agpsType, agpsStatus, suplIpAddr);
+ }
+
+ @NativeEntryPoint
+ void reportNmea(long timestamp) {
+ if (mItarSpeedLimitExceeded) {
+ return;
+ }
+
+ for (int i = 0; i < mNmeaCallbacks.length; i++) {
+ mNmeaCallbacks[i].onReportNmea(timestamp);
+ }
+ }
+
+ @NativeEntryPoint
+ void reportMeasurementData(GnssMeasurementsEvent event) {
+ if (mItarSpeedLimitExceeded) {
+ return;
+ }
+
+ for (int i = 0; i < mMeasurementCallbacks.length; i++) {
+ mMeasurementCallbacks[i].onReportMeasurements(event);
+ }
+ }
+
+ @NativeEntryPoint
+ void reportAntennaInfo(List<GnssAntennaInfo> antennaInfos) {
+ for (int i = 0; i < mAntennaInfoCallbacks.length; i++) {
+ mAntennaInfoCallbacks[i].onReportAntennaInfo(antennaInfos);
+ }
+ }
+
+ @NativeEntryPoint
+ void reportNavigationMessage(GnssNavigationMessage event) {
+ if (mItarSpeedLimitExceeded) {
+ return;
+ }
+
+ for (int i = 0; i < mNavigationMessageCallbacks.length; i++) {
+ mNavigationMessageCallbacks[i].onReportNavigationMessage(event);
+ }
+ }
+
+ @NativeEntryPoint
+ void setTopHalCapabilities(@GnssCapabilities.TopHalCapabilityFlags int capabilities) {
+ GnssCapabilities oldCapabilities = mCapabilities;
+ mCapabilities = oldCapabilities.withTopHalFlags(capabilities);
+ onCapabilitiesChanged(oldCapabilities, mCapabilities);
+ }
+
+ @NativeEntryPoint
+ void setSubHalMeasurementCorrectionsCapabilities(
+ @GnssCapabilities.SubHalMeasurementCorrectionsCapabilityFlags int capabilities) {
+ GnssCapabilities oldCapabilities = mCapabilities;
+ mCapabilities = oldCapabilities.withSubHalMeasurementCorrectionsFlags(capabilities);
+ onCapabilitiesChanged(oldCapabilities, mCapabilities);
+ }
+
+ @NativeEntryPoint
+ void setSubHalPowerIndicationCapabilities(
+ @GnssCapabilities.SubHalPowerCapabilityFlags int capabilities) {
+ GnssCapabilities oldCapabilities = mCapabilities;
+ mCapabilities = oldCapabilities.withSubHalPowerFlags(capabilities);
+ onCapabilitiesChanged(oldCapabilities, mCapabilities);
+ }
+
+ private void onCapabilitiesChanged(GnssCapabilities oldCapabilities,
+ GnssCapabilities newCapabilities) {
+ if (newCapabilities.equals(oldCapabilities)) {
+ return;
+ }
+
+ Log.i(TAG, "gnss capabilities changed to " + newCapabilities);
+
+ for (int i = 0; i < mBaseCallbacks.length; i++) {
+ mBaseCallbacks[i].onCapabilitiesChanged(oldCapabilities, newCapabilities);
+ }
+ }
+
+ @NativeEntryPoint
+ void reportGnssPowerStats(GnssPowerStats powerStats) {
+ mPowerStats = powerStats;
+ }
+
+ @NativeEntryPoint
+ void setGnssYearOfHardware(int year) {
+ mHardwareYear = year;
+ }
+
+ @NativeEntryPoint
+ private void setGnssHardwareModelName(String modelName) {
+ mHardwareModelName = modelName;
+ }
+
+ @NativeEntryPoint
+ void reportLocationBatch(Location[] locations) {
+ for (int i = 0; i < mLocationCallbacks.length; i++) {
+ mLocationCallbacks[i].onReportLocations(locations);
+ }
+ }
+
+ @NativeEntryPoint
+ void psdsDownloadRequest(int psdsType) {
+ mPsdsCallbacks.onRequestPsdsDownload(psdsType);
+ }
+
+ @NativeEntryPoint
+ void reportGeofenceTransition(int geofenceId, Location location, int transition,
+ long transitionTimestamp) {
+ mGeofenceCallbacks.onReportGeofenceTransition(geofenceId, location, transition,
+ transitionTimestamp);
+ }
+
+ @NativeEntryPoint
+ void reportGeofenceStatus(int status, Location location) {
+ mGeofenceCallbacks.onReportGeofenceStatus(status, location);
+ }
+
+ @NativeEntryPoint
+ void reportGeofenceAddStatus(int geofenceId, @GeofenceCallbacks.GeofenceStatus int status) {
+ mGeofenceCallbacks.onReportGeofenceAddStatus(geofenceId, status);
+ }
+
+ @NativeEntryPoint
+ void reportGeofenceRemoveStatus(int geofenceId, @GeofenceCallbacks.GeofenceStatus int status) {
+ mGeofenceCallbacks.onReportGeofenceRemoveStatus(geofenceId, status);
+ }
+
+ @NativeEntryPoint
+ void reportGeofencePauseStatus(int geofenceId, @GeofenceCallbacks.GeofenceStatus int status) {
+ mGeofenceCallbacks.onReportGeofencePauseStatus(geofenceId, status);
+ }
+
+ @NativeEntryPoint
+ void reportGeofenceResumeStatus(int geofenceId, @GeofenceCallbacks.GeofenceStatus int status) {
+ mGeofenceCallbacks.onReportGeofenceResumeStatus(geofenceId, status);
+ }
+
+ @NativeEntryPoint
+ void reportNiNotification(int notificationId, int niType, int notifyFlags,
+ int timeout, int defaultResponse, String requestorId, String text,
+ int requestorIdEncoding, int textEncoding) {
+ mNotificationCallbacks.onReportNiNotification(notificationId, niType, notifyFlags, timeout,
+ defaultResponse, requestorId, text, requestorIdEncoding, textEncoding);
+ }
+
+ @NativeEntryPoint
+ void requestSetID(int flags) {
+ mAGpsCallbacks.onRequestSetID(flags);
+ }
+
+ @NativeEntryPoint
+ void requestLocation(boolean independentFromGnss, boolean isUserEmergency) {
+ mLocationRequestCallbacks.onRequestLocation(independentFromGnss, isUserEmergency);
+ }
+
+ @NativeEntryPoint
+ void requestUtcTime() {
+ mTimeCallbacks.onRequestUtcTime();
+ }
+
+ @NativeEntryPoint
+ void requestRefLocation() {
+ mLocationRequestCallbacks.onRequestRefLocation();
+ }
+
+ @NativeEntryPoint
+ void reportNfwNotification(String proxyAppPackageName, byte protocolStack,
+ String otherProtocolStackName, byte requestor, String requestorId,
+ byte responseType, boolean inEmergencyMode, boolean isCachedLocation) {
+ mNotificationCallbacks.onReportNfwNotification(proxyAppPackageName, protocolStack,
+ otherProtocolStackName, requestor, requestorId, responseType, inEmergencyMode,
+ isCachedLocation);
+ }
+
+ @NativeEntryPoint
+ boolean isInEmergencySession() {
+ return mEmergencyHelper.isInEmergency(mConfiguration.getEsExtensionSec());
+ }
+
+ /**
+ * Encapsulates actual HAL methods for testing purposes.
+ */
+ @VisibleForTesting
+ public static class GnssHal {
+
+ protected GnssHal() {}
+
+ protected void classInitOnce() {
+ native_class_init_once();
+ }
+
+ protected boolean isSupported() {
+ return native_is_supported();
+ }
+
+ protected void initOnce(GnssNative gnssNative, boolean reinitializeGnssServiceHandle) {
+ gnssNative.native_init_once(reinitializeGnssServiceHandle);
+ }
+
+ protected boolean init() {
+ return native_init();
+ }
+
+ protected void cleanup() {
+ native_cleanup();
+ }
+
+ protected boolean start() {
+ return native_start();
+ }
+
+ protected boolean stop() {
+ return native_stop();
+ }
+
+ protected boolean setPositionMode(@GnssPositionMode int mode,
+ @GnssPositionRecurrence int recurrence, int minInterval, int preferredAccuracy,
+ int preferredTime, boolean lowPowerMode) {
+ return native_set_position_mode(mode, recurrence, minInterval, preferredAccuracy,
+ preferredTime, lowPowerMode);
+ }
+
+ protected String getInternalState() {
+ return native_get_internal_state();
+ }
+
+ protected void deleteAidingData(@GnssAidingTypeFlags int flags) {
+ native_delete_aiding_data(flags);
+ }
+
+ protected int readNmea(byte[] buffer, int bufferSize) {
+ return native_read_nmea(buffer, bufferSize);
+ }
+
+ protected void injectLocation(double latitude, double longitude, float accuracy) {
+ native_inject_location(latitude, longitude, accuracy);
+ }
+
+ protected void injectBestLocation(@GnssLocationFlags int gnssLocationFlags, double latitude,
+ double longitude, double altitude, float speed, float bearing,
+ float horizontalAccuracy, float verticalAccuracy, float speedAccuracy,
+ float bearingAccuracy, long timestamp, @GnssRealtimeFlags int elapsedRealtimeFlags,
+ long elapsedRealtimeNanos, double elapsedRealtimeUncertaintyNanos) {
+ native_inject_best_location(gnssLocationFlags, latitude, longitude, altitude, speed,
+ bearing, horizontalAccuracy, verticalAccuracy, speedAccuracy, bearingAccuracy,
+ timestamp, elapsedRealtimeFlags, elapsedRealtimeNanos,
+ elapsedRealtimeUncertaintyNanos);
+ }
+
+ protected void injectTime(long time, long timeReference, int uncertainty) {
+ native_inject_time(time, timeReference, uncertainty);
+ }
+
+ protected boolean isNavigationMessageCollectionSupported() {
+ return native_is_navigation_message_supported();
+ }
+
+ protected boolean startNavigationMessageCollection() {
+ return native_start_navigation_message_collection();
+ }
+
+ protected boolean stopNavigationMessageCollection() {
+ return native_stop_navigation_message_collection();
+ }
+
+ protected boolean isAntennaInfoListeningSupported() {
+ return native_is_antenna_info_supported();
+ }
+
+ protected boolean startAntennaInfoListening() {
+ return native_start_antenna_info_listening();
+ }
+
+ protected boolean stopAntennaInfoListening() {
+ return native_stop_antenna_info_listening();
+ }
+
+ protected boolean isMeasurementSupported() {
+ return native_is_measurement_supported();
+ }
+
+ protected boolean startMeasurementCollection(boolean enableFullTracking) {
+ return native_start_measurement_collection(enableFullTracking);
+ }
+
+ protected boolean stopMeasurementCollection() {
+ return native_stop_measurement_collection();
+ }
+
+ protected boolean isMeasurementCorrectionsSupported() {
+ return native_is_measurement_corrections_supported();
+ }
+
+ protected boolean injectMeasurementCorrections(GnssMeasurementCorrections corrections) {
+ return native_inject_measurement_corrections(corrections);
+ }
+
+ protected int getBatchSize() {
+ return native_get_batch_size();
+ }
+
+ protected boolean initBatching() {
+ return native_init_batching();
+ }
+
+ protected void cleanupBatching() {
+ native_cleanup_batching();
+ }
+
+ protected boolean startBatch(long periodNanos, boolean wakeOnFifoFull) {
+ return native_start_batch(periodNanos, wakeOnFifoFull);
+ }
+
+ protected void flushBatch() {
+ native_flush_batch();
+ }
+
+ protected void stopBatch() {
+ native_stop_batch();
+ }
+
+ protected boolean isGeofencingSupported() {
+ return native_is_geofence_supported();
+ }
+
+ protected boolean addGeofence(int geofenceId, double latitude, double longitude,
+ double radius, int lastTransition, int monitorTransitions,
+ int notificationResponsiveness, int unknownTimer) {
+ return native_add_geofence(geofenceId, latitude, longitude, radius, lastTransition,
+ monitorTransitions, notificationResponsiveness, unknownTimer);
+ }
+
+ protected boolean resumeGeofence(int geofenceId, int monitorTransitions) {
+ return native_resume_geofence(geofenceId, monitorTransitions);
+ }
+
+ protected boolean pauseGeofence(int geofenceId) {
+ return native_pause_geofence(geofenceId);
+ }
+
+ protected boolean removeGeofence(int geofenceId) {
+ return native_remove_geofence(geofenceId);
+ }
+
+ protected boolean isGnssVisibilityControlSupported() {
+ return native_is_gnss_visibility_control_supported();
+ }
+
+ protected void sendNiResponse(int notificationId, int userResponse) {
+ native_send_ni_response(notificationId, userResponse);
+ }
+
+ protected void requestPowerStats() {
+ native_request_power_stats();
+ }
+
+ protected void setAgpsServer(int type, String hostname, int port) {
+ native_set_agps_server(type, hostname, port);
+ }
+
+ protected void setAgpsSetId(@AgpsSetIdType int type, String setId) {
+ native_agps_set_id(type, setId);
+ }
+
+ protected void setAgpsReferenceLocationCellId(@AgpsReferenceLocationType int type, int mcc,
+ int mnc, int lac, int cid) {
+ native_agps_set_ref_location_cellid(type, mcc, mnc, lac, cid);
+ }
+
+ protected boolean isPsdsSupported() {
+ return native_supports_psds();
+ }
+
+ protected void injectPsdsData(byte[] data, int length, int psdsType) {
+ native_inject_psds_data(data, length, psdsType);
+ }
+ }
+
+ // basic APIs
+
+ private static native void native_class_init_once();
+
+ private static native boolean native_is_supported();
+
+ private native void native_init_once(boolean reinitializeGnssServiceHandle);
+
+ private static native boolean native_init();
+
+ private static native void native_cleanup();
+
+ private static native boolean native_start();
+
+ private static native boolean native_stop();
+
+ private static native boolean native_set_position_mode(int mode, int recurrence,
+ int minInterval, int preferredAccuracy, int preferredTime, boolean lowPowerMode);
+
+ private static native String native_get_internal_state();
+
+ private static native void native_delete_aiding_data(int flags);
+
+ // NMEA APIs
+
+ private static native int native_read_nmea(byte[] buffer, int bufferSize);
+
+ // location injection APIs
+
+ private static native void native_inject_location(double latitude, double longitude,
+ float accuracy);
+
+
+ private static native void native_inject_best_location(
+ int gnssLocationFlags, double latitudeDegrees, double longitudeDegrees,
+ double altitudeMeters, float speedMetersPerSec, float bearingDegrees,
+ float horizontalAccuracyMeters, float verticalAccuracyMeters,
+ float speedAccuracyMetersPerSecond, float bearingAccuracyDegrees,
+ long timestamp, int elapsedRealtimeFlags, long elapsedRealtimeNanos,
+ double elapsedRealtimeUncertaintyNanos);
+
+ // time injection APIs
+
+ private static native void native_inject_time(long time, long timeReference, int uncertainty);
+
+ // navigation message APIs
+
+ private static native boolean native_is_navigation_message_supported();
+
+ private static native boolean native_start_navigation_message_collection();
+
+ private static native boolean native_stop_navigation_message_collection();
+
+ // antenna info APIS
+
+ private static native boolean native_is_antenna_info_supported();
+
+ private static native boolean native_start_antenna_info_listening();
+
+ private static native boolean native_stop_antenna_info_listening();
+
+ // measurement APIs
+
+ private static native boolean native_is_measurement_supported();
+
+ private static native boolean native_start_measurement_collection(boolean enableFullTracking);
+
+ private static native boolean native_stop_measurement_collection();
+
+ // measurement corrections APIs
+
+ private static native boolean native_is_measurement_corrections_supported();
+
+ private static native boolean native_inject_measurement_corrections(
+ GnssMeasurementCorrections corrections);
+
+ // batching APIs
+
+ private static native boolean native_init_batching();
+
+ private static native void native_cleanup_batching();
+
+ private static native boolean native_start_batch(long periodNanos, boolean wakeOnFifoFull);
+
+ private static native void native_flush_batch();
+
+ private static native boolean native_stop_batch();
+
+ private static native int native_get_batch_size();
+
+ // geofence APIs
+
+ private static native boolean native_is_geofence_supported();
+
+ private static native boolean native_add_geofence(int geofenceId, double latitude,
+ double longitude, double radius, int lastTransition, int monitorTransitions,
+ int notificationResponsivenes, int unknownTimer);
+
+ private static native boolean native_resume_geofence(int geofenceId, int monitorTransitions);
+
+ private static native boolean native_pause_geofence(int geofenceId);
+
+ private static native boolean native_remove_geofence(int geofenceId);
+
+ // network initiated (NI) APIs
+
+ private static native boolean native_is_gnss_visibility_control_supported();
+
+ private static native void native_send_ni_response(int notificationId, int userResponse);
+
+ // power stats APIs
+
+ private static native void native_request_power_stats();
+
+ // AGPS APIs
+
+ private static native void native_set_agps_server(int type, String hostname, int port);
+
+ private static native void native_agps_set_id(int type, String setid);
+
+ private static native void native_agps_set_ref_location_cellid(int type, int mcc, int mnc,
+ int lac, int cid);
+
+ // PSDS APIs
+
+ private static native boolean native_supports_psds();
+
+ private static native void native_inject_psds_data(byte[] data, int length, int psdsType);
+}
diff --git a/location/java/com/android/internal/location/timezone/ILocationTimeZoneProviderManager.aidl b/services/core/java/com/android/server/location/injector/EmergencyHelper.java
similarity index 64%
rename from location/java/com/android/internal/location/timezone/ILocationTimeZoneProviderManager.aidl
rename to services/core/java/com/android/server/location/injector/EmergencyHelper.java
index b5450b7..be4bf50 100644
--- a/location/java/com/android/internal/location/timezone/ILocationTimeZoneProviderManager.aidl
+++ b/services/core/java/com/android/server/location/injector/EmergencyHelper.java
@@ -14,14 +14,16 @@
* limitations under the License.
*/
-package com.android.internal.location.timezone;
-
-import com.android.internal.location.timezone.LocationTimeZoneEvent;
+package com.android.server.location.injector;
/**
- * Binder interface for the manager of location time zone provider implementations.
- * @hide
+ * Provides helpers for emergency sessions.
*/
-interface ILocationTimeZoneProviderManager {
- void onLocationTimeZoneEvent(in LocationTimeZoneEvent locationTimeZoneEvent);
+public abstract class EmergencyHelper {
+
+ /**
+ * Returns true if the device is in an emergency session, or if an emergency session ended
+ * within the given extension time.
+ */
+ public abstract boolean isInEmergency(long extensionTimeMs);
}
diff --git a/services/core/java/com/android/server/location/injector/Injector.java b/services/core/java/com/android/server/location/injector/Injector.java
index c42396d..03938b2 100644
--- a/services/core/java/com/android/server/location/injector/Injector.java
+++ b/services/core/java/com/android/server/location/injector/Injector.java
@@ -51,6 +51,9 @@
/** Returns a LocationAttributionHelper. */
LocationAttributionHelper getLocationAttributionHelper();
+ /** Returns an EmergencyHelper. */
+ EmergencyHelper getEmergencyHelper();
+
/** Returns a LocationUsageLogger. */
LocationUsageLogger getLocationUsageLogger();
diff --git a/services/core/java/com/android/server/location/injector/SystemEmergencyHelper.java b/services/core/java/com/android/server/location/injector/SystemEmergencyHelper.java
new file mode 100644
index 0000000..05d0aef
--- /dev/null
+++ b/services/core/java/com/android/server/location/injector/SystemEmergencyHelper.java
@@ -0,0 +1,94 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.location.injector;
+
+import android.content.BroadcastReceiver;
+import android.content.Context;
+import android.content.Intent;
+import android.content.IntentFilter;
+import android.os.SystemClock;
+import android.telephony.PhoneStateListener;
+import android.telephony.TelephonyManager;
+
+import com.android.server.FgThread;
+
+import java.util.Objects;
+
+/**
+ * Provides helpers for emergency sessions.
+ */
+public class SystemEmergencyHelper extends EmergencyHelper {
+
+ private final Context mContext;
+
+ private TelephonyManager mTelephonyManager;
+
+ private boolean mIsInEmergencyCall;
+ private long mEmergencyCallEndRealtimeMs = Long.MIN_VALUE;
+
+ public SystemEmergencyHelper(Context context) {
+ mContext = context;
+ }
+
+ /** Called when system is ready. */
+ public void onSystemReady() {
+ if (mTelephonyManager != null) {
+ return;
+ }
+
+ mTelephonyManager = Objects.requireNonNull(
+ mContext.getSystemService(TelephonyManager.class));
+
+ // TODO: this doesn't account for multisim phones
+
+ mTelephonyManager.registerPhoneStateListener(FgThread.getExecutor(),
+ new EmergencyCallPhoneStateListener());
+ mContext.registerReceiver(new BroadcastReceiver() {
+ @Override
+ public void onReceive(Context context, Intent intent) {
+ if (!Intent.ACTION_NEW_OUTGOING_CALL.equals(intent.getAction())) {
+ return;
+ }
+
+ mIsInEmergencyCall = mTelephonyManager.isEmergencyNumber(
+ intent.getStringExtra(Intent.EXTRA_PHONE_NUMBER));
+ }
+ }, new IntentFilter(Intent.ACTION_NEW_OUTGOING_CALL));
+ }
+
+ @Override
+ public boolean isInEmergency(long extensionTimeMs) {
+ return mIsInEmergencyCall
+ || ((SystemClock.elapsedRealtime() - mEmergencyCallEndRealtimeMs) < extensionTimeMs)
+ || mTelephonyManager.getEmergencyCallbackMode()
+ || mTelephonyManager.isInEmergencySmsMode();
+ }
+
+ private class EmergencyCallPhoneStateListener extends PhoneStateListener implements
+ PhoneStateListener.CallStateChangedListener {
+
+ @Override
+ public void onCallStateChanged(int state, String incomingNumber) {
+ if (state == TelephonyManager.CALL_STATE_IDLE) {
+ if (mIsInEmergencyCall) {
+ mEmergencyCallEndRealtimeMs = SystemClock.elapsedRealtime();
+ mIsInEmergencyCall = false;
+ }
+ }
+ }
+ }
+}
diff --git a/services/core/java/com/android/server/location/provider/AbstractLocationProvider.java b/services/core/java/com/android/server/location/provider/AbstractLocationProvider.java
index d06f54d..5364feb 100644
--- a/services/core/java/com/android/server/location/provider/AbstractLocationProvider.java
+++ b/services/core/java/com/android/server/location/provider/AbstractLocationProvider.java
@@ -18,11 +18,11 @@
import android.annotation.Nullable;
import android.location.LocationResult;
+import android.location.ProviderProperties;
import android.location.util.identity.CallerIdentity;
import android.os.Binder;
import android.os.Bundle;
-import com.android.internal.location.ProviderProperties;
import com.android.internal.location.ProviderRequest;
import com.android.internal.util.Preconditions;
@@ -90,7 +90,10 @@
this.identity = identity;
}
- State withAllowed(boolean allowed) {
+ /**
+ * Returns a state the same as the current but with allowed set as specified.
+ */
+ public State withAllowed(boolean allowed) {
if (allowed == this.allowed) {
return this;
} else {
@@ -98,7 +101,10 @@
}
}
- State withProperties(@Nullable ProviderProperties properties) {
+ /**
+ * Returns a state the same as the current but with properties set as specified.
+ */
+ public State withProperties(@Nullable ProviderProperties properties) {
if (Objects.equals(properties, this.properties)) {
return this;
} else {
@@ -106,7 +112,10 @@
}
}
- State withIdentity(@Nullable CallerIdentity identity) {
+ /**
+ * Returns a state the same as the current but with an identity set as specified.
+ */
+ public State withIdentity(@Nullable CallerIdentity identity) {
if (Objects.equals(identity, this.identity)) {
return this;
} else {
@@ -175,28 +184,21 @@
private final LocationProviderController mController;
-
- /**
- * See {@link #AbstractLocationProvider(Executor, CallerIdentity)}.
- */
- protected AbstractLocationProvider(Executor executor) {
- this(executor, null);
- }
-
/**
* Creates a new location provider.
*
* All callback methods will be invoked on the given executor. A direct executor may be provided
* only if the provider can guarantee that all callback methods will never synchronously invoke
- * any command method (that changes provider state, or reports a location, etc...). If this
- * invariant is not held, use a normal executor or risk deadlock.
+ * any {@link LocationProviderController} methods. If this invariant is not held, use a normal
+ * executor or risk deadlock.
*
- * An optional identity may be provided to initialize the location provider.
+ * An optional identity and properties may be provided to initialize the location provider.
*/
- protected AbstractLocationProvider(Executor executor, CallerIdentity identity) {
+ protected AbstractLocationProvider(Executor executor, @Nullable CallerIdentity identity,
+ @Nullable ProviderProperties properties) {
mExecutor = executor;
- mInternalState = new AtomicReference<>(
- new InternalState(null, State.EMPTY_STATE.withIdentity(identity)));
+ mInternalState = new AtomicReference<>(new InternalState(null,
+ State.EMPTY_STATE.withIdentity(identity).withProperties(properties)));
mController = new Controller();
}
@@ -209,46 +211,23 @@
return mController;
}
- /**
- * Sets the state of the provider to the new state.
- */
- protected void setState(State newState) {
- InternalState oldInternalState = mInternalState.getAndUpdate(
- internalState -> internalState.withState(newState));
- if (newState.equals(oldInternalState.state)) {
+ protected void setState(UnaryOperator<State> operator) {
+ AtomicReference<State> oldStateRef = new AtomicReference<>();
+ InternalState newInternalState = mInternalState.updateAndGet(
+ internalState -> {
+ oldStateRef.set(internalState.state);
+ return internalState.withState(operator);
+ });
+ State oldState = oldStateRef.get();
+
+ if (oldState.equals(newInternalState.state)) {
return;
}
- // we know that we only updated the state, so the listener for the old state is the same as
- // the listener for the new state.
- if (oldInternalState.listener != null) {
+ if (newInternalState.listener != null) {
final long identity = Binder.clearCallingIdentity();
try {
- oldInternalState.listener.onStateChanged(oldInternalState.state, newState);
- } finally {
- Binder.restoreCallingIdentity(identity);
- }
- }
- }
-
- private void setState(UnaryOperator<State> operator) {
- InternalState oldInternalState = mInternalState.getAndUpdate(
- internalState -> internalState.withState(operator));
-
- // recreate the new state from our knowledge of the old state - unfortunately may result in
- // an extra allocation, but oh well...
- State newState = operator.apply(oldInternalState.state);
-
- if (newState.equals(oldInternalState.state)) {
- return;
- }
-
- // we know that we only updated the state, so the listener for the old state is the same as
- // the listener for the new state.
- if (oldInternalState.listener != null) {
- final long identity = Binder.clearCallingIdentity();
- try {
- oldInternalState.listener.onStateChanged(oldInternalState.state, newState);
+ newInternalState.listener.onStateChanged(oldState, newInternalState.state);
} finally {
Binder.restoreCallingIdentity(identity);
}
@@ -279,7 +258,7 @@
/**
* Call this method to report a change in provider properties.
*/
- protected void setProperties(ProviderProperties properties) {
+ protected void setProperties(@Nullable ProviderProperties properties) {
setState(state -> state.withProperties(properties));
}
@@ -293,7 +272,7 @@
/**
* Call this method to report a change in provider packages.
*/
- protected void setIdentity(CallerIdentity identity) {
+ protected void setIdentity(@Nullable CallerIdentity identity) {
setState(state -> state.withIdentity(identity));
}
diff --git a/services/core/java/com/android/server/location/provider/LocationProviderManager.java b/services/core/java/com/android/server/location/provider/LocationProviderManager.java
index 2fe8bcc..858b762 100644
--- a/services/core/java/com/android/server/location/provider/LocationProviderManager.java
+++ b/services/core/java/com/android/server/location/provider/LocationProviderManager.java
@@ -46,7 +46,6 @@
import android.app.PendingIntent;
import android.content.Context;
import android.content.Intent;
-import android.location.Criteria;
import android.location.ILocationCallback;
import android.location.ILocationListener;
import android.location.LastLocationRequest;
@@ -56,6 +55,7 @@
import android.location.LocationManagerInternal.ProviderEnabledListener;
import android.location.LocationRequest;
import android.location.LocationResult;
+import android.location.ProviderProperties;
import android.location.util.identity.CallerIdentity;
import android.os.Binder;
import android.os.Build;
@@ -82,7 +82,6 @@
import android.util.TimeUtils;
import com.android.internal.annotations.GuardedBy;
-import com.android.internal.location.ProviderProperties;
import com.android.internal.location.ProviderRequest;
import com.android.internal.util.Preconditions;
import com.android.server.FgThread;
@@ -452,7 +451,7 @@
return isActive()
&& getRequest().getIntervalMillis() < MAX_HIGH_POWER_INTERVAL_MS
- && getProperties().getPowerRequirement() == Criteria.POWER_HIGH;
+ && getProperties().getPowerUsage() == ProviderProperties.POWER_USAGE_HIGH;
}
@GuardedBy("mLock")
@@ -1358,6 +1357,8 @@
public boolean isEnabled(int userId) {
if (userId == UserHandle.USER_NULL) {
return false;
+ } else if (userId == UserHandle.USER_CURRENT) {
+ return isEnabled(mUserHelper.getCurrentUserId());
}
Preconditions.checkArgument(userId >= 0);
@@ -1519,6 +1520,9 @@
}
}
return lastLocation;
+ } else if (userId == UserHandle.USER_CURRENT) {
+ return getLastLocationUnsafe(mUserHelper.getCurrentUserId(), permissionLevel,
+ ignoreLocationSettings, maximumAgeMs);
}
Preconditions.checkArgument(userId >= 0);
@@ -1561,6 +1565,9 @@
setLastLocation(location, runningUserIds[i]);
}
return;
+ } else if (userId == UserHandle.USER_CURRENT) {
+ setLastLocation(location, mUserHelper.getCurrentUserId());
+ return;
}
Preconditions.checkArgument(userId >= 0);
diff --git a/services/core/java/com/android/server/location/provider/MockLocationProvider.java b/services/core/java/com/android/server/location/provider/MockLocationProvider.java
index 0c6d5dc..f9aa402 100644
--- a/services/core/java/com/android/server/location/provider/MockLocationProvider.java
+++ b/services/core/java/com/android/server/location/provider/MockLocationProvider.java
@@ -21,10 +21,10 @@
import android.annotation.Nullable;
import android.location.Location;
import android.location.LocationResult;
+import android.location.ProviderProperties;
import android.location.util.identity.CallerIdentity;
import android.os.Bundle;
-import com.android.internal.location.ProviderProperties;
import com.android.internal.location.ProviderRequest;
import java.io.FileDescriptor;
@@ -41,8 +41,7 @@
public MockLocationProvider(ProviderProperties properties, CallerIdentity identity) {
// using a direct executor is ok because this class has no locks that could deadlock
- super(DIRECT_EXECUTOR, identity);
- setProperties(properties);
+ super(DIRECT_EXECUTOR, identity, properties);
}
/** Sets the allowed state of this mock provider. */
diff --git a/services/core/java/com/android/server/location/provider/MockableLocationProvider.java b/services/core/java/com/android/server/location/provider/MockableLocationProvider.java
index 79f641f..c1b0abf 100644
--- a/services/core/java/com/android/server/location/provider/MockableLocationProvider.java
+++ b/services/core/java/com/android/server/location/provider/MockableLocationProvider.java
@@ -21,11 +21,11 @@
import android.annotation.Nullable;
import android.location.Location;
import android.location.LocationResult;
+import android.location.ProviderProperties;
import android.location.util.identity.CallerIdentity;
import android.os.Bundle;
import com.android.internal.annotations.GuardedBy;
-import com.android.internal.location.ProviderProperties;
import com.android.internal.location.ProviderRequest;
import com.android.internal.util.Preconditions;
@@ -75,7 +75,7 @@
public MockableLocationProvider(Object ownerLock) {
// using a direct executor is acceptable because all inbound calls are delegated to the
// actual provider implementations which will use their own executors
- super(DIRECT_EXECUTOR);
+ super(DIRECT_EXECUTOR, null, null);
mOwnerLock = ownerLock;
mRequest = ProviderRequest.EMPTY_REQUEST;
}
@@ -167,7 +167,7 @@
newState = State.EMPTY_STATE;
}
- setState(newState);
+ setState(prevState -> newState);
}
/**
@@ -325,7 +325,7 @@
return;
}
- setState(newState);
+ setState(prevState -> newState);
}
}
diff --git a/services/core/java/com/android/server/location/provider/PassiveLocationProvider.java b/services/core/java/com/android/server/location/provider/PassiveLocationProvider.java
index 0e8b40b..1f4c4cf 100644
--- a/services/core/java/com/android/server/location/provider/PassiveLocationProvider.java
+++ b/services/core/java/com/android/server/location/provider/PassiveLocationProvider.java
@@ -19,12 +19,11 @@
import static com.android.internal.util.ConcurrentUtils.DIRECT_EXECUTOR;
import android.content.Context;
-import android.location.Criteria;
import android.location.LocationResult;
+import android.location.ProviderProperties;
import android.location.util.identity.CallerIdentity;
import android.os.Bundle;
-import com.android.internal.location.ProviderProperties;
import com.android.internal.location.ProviderRequest;
import java.io.FileDescriptor;
@@ -47,14 +46,12 @@
/* supportsAltitude = */false,
/* supportsSpeed = */false,
/* supportsBearing = */false,
- Criteria.POWER_LOW,
- Criteria.ACCURACY_COARSE);
+ ProviderProperties.POWER_USAGE_LOW,
+ ProviderProperties.ACCURACY_COARSE);
public PassiveLocationProvider(Context context) {
// using a direct executor is ok because this class has no locks that could deadlock
- super(DIRECT_EXECUTOR, CallerIdentity.fromContext(context));
-
- setProperties(PROPERTIES);
+ super(DIRECT_EXECUTOR, CallerIdentity.fromContext(context), PROPERTIES);
setAllowed(true);
}
diff --git a/services/core/java/com/android/server/location/provider/proxy/ProxyLocationProvider.java b/services/core/java/com/android/server/location/provider/proxy/ProxyLocationProvider.java
index 6e92c8d..345fdc0 100644
--- a/services/core/java/com/android/server/location/provider/proxy/ProxyLocationProvider.java
+++ b/services/core/java/com/android/server/location/provider/proxy/ProxyLocationProvider.java
@@ -22,6 +22,7 @@
import android.content.ComponentName;
import android.content.Context;
import android.location.LocationResult;
+import android.location.ProviderProperties;
import android.location.util.identity.CallerIdentity;
import android.os.Binder;
import android.os.Bundle;
@@ -31,7 +32,6 @@
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.util.ArrayUtils;
import com.android.server.ServiceWatcher;
@@ -82,7 +82,7 @@
int nonOverlayPackageResId) {
// safe to use direct executor since our locks are not acquired in a code path invoked by
// our owning provider
- super(DIRECT_EXECUTOR);
+ super(DIRECT_EXECUTOR, null, null);
mContext = context;
mServiceWatcher = new ServiceWatcher(context, action, this::onBind,
@@ -116,7 +116,7 @@
synchronized (mLock) {
mProxy = null;
mService = null;
- setState(State.EMPTY_STATE);
+ setState(prevState -> State.EMPTY_STATE);
flushListeners = mFlushListeners.toArray(new Runnable[0]);
mFlushListeners.clear();
}
@@ -210,7 +210,8 @@
// executed on binder thread
@Override
- public void onSetIdentity(@Nullable String packageName, @Nullable String attributionTag) {
+ public void onInitialize(boolean allowed, ProviderProperties properties,
+ @Nullable String packageName, @Nullable String attributionTag) {
synchronized (mLock) {
if (mProxy != this) {
return;
@@ -226,7 +227,10 @@
identity = CallerIdentity.fromBinder(mContext, packageName, attributionTag);
}
- setIdentity(identity);
+ setState(prevState -> prevState
+ .withAllowed(allowed)
+ .withProperties(properties)
+ .withIdentity(identity));
}
}
@@ -238,14 +242,6 @@
return;
}
- // if no identity is set yet, set it now
- if (getIdentity() == null) {
- String packageName = guessPackageName(mContext, Binder.getCallingUid(),
- Objects.requireNonNull(mService).getPackageName());
- // unsafe is ok since the package is coming direct from the package manager here
- setIdentity(CallerIdentity.fromBinderUnsafe(packageName, null));
- }
-
setProperties(properties);
}
}
diff --git a/services/core/java/com/android/server/location/timezone/BinderLocationTimeZoneProvider.java b/services/core/java/com/android/server/location/timezone/BinderLocationTimeZoneProvider.java
index b9c23b7..0881cd2 100644
--- a/services/core/java/com/android/server/location/timezone/BinderLocationTimeZoneProvider.java
+++ b/services/core/java/com/android/server/location/timezone/BinderLocationTimeZoneProvider.java
@@ -162,11 +162,6 @@
}
@Override
- void logWarn(String msg) {
- Slog.w(TAG, msg);
- }
-
- @Override
public void dump(@NonNull IndentingPrintWriter ipw, @Nullable String[] args) {
synchronized (mSharedLock) {
ipw.println("{BinderLocationTimeZoneProvider}");
diff --git a/services/core/java/com/android/server/location/timezone/LocationTimeZoneManagerService.java b/services/core/java/com/android/server/location/timezone/LocationTimeZoneManagerService.java
index ab64f97..a23b9d7 100644
--- a/services/core/java/com/android/server/location/timezone/LocationTimeZoneManagerService.java
+++ b/services/core/java/com/android/server/location/timezone/LocationTimeZoneManagerService.java
@@ -285,8 +285,12 @@
}
static void warnLog(String msg) {
+ warnLog(msg, null);
+ }
+
+ static void warnLog(String msg, @Nullable Throwable t) {
if (Log.isLoggable(TAG, Log.WARN)) {
- Slog.w(TAG, msg);
+ Slog.w(TAG, msg, t);
}
}
}
diff --git a/services/core/java/com/android/server/location/timezone/LocationTimeZoneProvider.java b/services/core/java/com/android/server/location/timezone/LocationTimeZoneProvider.java
index 8b51ab4..e55d1cc 100644
--- a/services/core/java/com/android/server/location/timezone/LocationTimeZoneProvider.java
+++ b/services/core/java/com/android/server/location/timezone/LocationTimeZoneProvider.java
@@ -17,6 +17,7 @@
package com.android.server.location.timezone;
import static com.android.server.location.timezone.LocationTimeZoneManagerService.debugLog;
+import static com.android.server.location.timezone.LocationTimeZoneManagerService.warnLog;
import static com.android.server.location.timezone.LocationTimeZoneProvider.ProviderState.PROVIDER_STATE_PERM_FAILED;
import static com.android.server.location.timezone.LocationTimeZoneProvider.ProviderState.PROVIDER_STATE_STARTED_CERTAIN;
import static com.android.server.location.timezone.LocationTimeZoneProvider.ProviderState.PROVIDER_STATE_STARTED_INITIALIZING;
@@ -345,12 +346,21 @@
}
mProviderListener = Objects.requireNonNull(providerListener);
ProviderState currentState = ProviderState.createStartingState(this);
- ProviderState newState = currentState.newState(
+ currentState = currentState.newState(
PROVIDER_STATE_STOPPED, null, null,
"initialize() called");
- setCurrentState(newState, false);
+ setCurrentState(currentState, false);
- onInitialize();
+ // Guard against uncaught exceptions due to initialization problems.
+ try {
+ onInitialize();
+ } catch (RuntimeException e) {
+ warnLog("Unable to initialize the provider", e);
+ currentState = currentState
+ .newState(PROVIDER_STATE_PERM_FAILED, null, null,
+ "Provider failed to initialize");
+ setCurrentState(currentState, true);
+ }
}
}
@@ -498,7 +508,7 @@
case PROVIDER_STATE_PERM_FAILED: {
// After entering perm failed, there is nothing to do. The remote peer is
// supposed to stop sending events after it has reported perm failure.
- logWarn("handleTimeZoneProviderEvent: Event=" + timeZoneProviderEvent
+ warnLog("handleTimeZoneProviderEvent: Event=" + timeZoneProviderEvent
+ " received for provider=" + this + " when in failed state");
return;
}
@@ -509,7 +519,7 @@
+ " Failure event=" + timeZoneProviderEvent
+ " received for stopped provider=" + this
+ ", entering permanently failed state";
- logWarn(msg);
+ warnLog(msg);
ProviderState newState = currentState.newState(
PROVIDER_STATE_PERM_FAILED, null, null, msg);
setCurrentState(newState, true);
@@ -522,7 +532,7 @@
case EVENT_TYPE_UNCERTAIN: {
// Any geolocation-related events received for a stopped provider are
// ignored: they should not happen.
- logWarn("handleTimeZoneProviderEvent:"
+ warnLog("handleTimeZoneProviderEvent:"
+ " event=" + timeZoneProviderEvent
+ " received for stopped provider=" + this
+ ", ignoring");
@@ -544,7 +554,7 @@
+ " Failure event=" + timeZoneProviderEvent
+ " received for provider=" + this
+ ", entering permanently failed state";
- logWarn(msg);
+ warnLog(msg);
ProviderState newState = currentState.newState(
PROVIDER_STATE_PERM_FAILED, null, null, msg);
setCurrentState(newState, true);
@@ -584,11 +594,6 @@
}
}
- /**
- * Implemented by subclasses.
- */
- abstract void logWarn(String msg);
-
@GuardedBy("mSharedLock")
private void assertIsStarted() {
ProviderState currentState = mCurrentState.get();
diff --git a/services/core/java/com/android/server/location/timezone/LocationTimeZoneProviderProxy.java b/services/core/java/com/android/server/location/timezone/LocationTimeZoneProviderProxy.java
index 91b52f1..16f9e97 100644
--- a/services/core/java/com/android/server/location/timezone/LocationTimeZoneProviderProxy.java
+++ b/services/core/java/com/android/server/location/timezone/LocationTimeZoneProviderProxy.java
@@ -79,8 +79,8 @@
throw new IllegalStateException("listener already set");
}
this.mListener = listener;
+ onInitialize();
}
- onInitialize();
}
/**
diff --git a/services/core/java/com/android/server/location/timezone/NullLocationTimeZoneProvider.java b/services/core/java/com/android/server/location/timezone/NullLocationTimeZoneProvider.java
index e11a7ce..4b321e6 100644
--- a/services/core/java/com/android/server/location/timezone/NullLocationTimeZoneProvider.java
+++ b/services/core/java/com/android/server/location/timezone/NullLocationTimeZoneProvider.java
@@ -21,7 +21,6 @@
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.util.IndentingPrintWriter;
-import android.util.Slog;
import java.time.Duration;
@@ -74,11 +73,6 @@
}
@Override
- void logWarn(String msg) {
- Slog.w(TAG, msg);
- }
-
- @Override
public void dump(@NonNull IndentingPrintWriter ipw, @Nullable String[] args) {
synchronized (mSharedLock) {
ipw.println("{Stubbed LocationTimeZoneProvider}");
diff --git a/services/core/java/com/android/server/location/timezone/RealLocationTimeZoneProviderProxy.java b/services/core/java/com/android/server/location/timezone/RealLocationTimeZoneProviderProxy.java
index 6cc148a..231136bc 100644
--- a/services/core/java/com/android/server/location/timezone/RealLocationTimeZoneProviderProxy.java
+++ b/services/core/java/com/android/server/location/timezone/RealLocationTimeZoneProviderProxy.java
@@ -16,10 +16,18 @@
package com.android.server.location.timezone;
+import static android.content.pm.PackageManager.PERMISSION_GRANTED;
+
+import static com.android.server.location.timezone.LocationTimeZoneManagerService.warnLog;
+
+import android.Manifest;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.content.ComponentName;
import android.content.Context;
+import android.content.pm.PackageManager;
+import android.content.pm.ResolveInfo;
+import android.content.pm.ServiceInfo;
import android.os.Handler;
import android.os.IBinder;
import android.os.RemoteException;
@@ -32,6 +40,7 @@
import com.android.server.ServiceWatcher;
import java.util.Objects;
+import java.util.function.Predicate;
/**
* System server-side proxy for ITimeZoneProvider implementations, i.e. this provides the
@@ -57,8 +66,38 @@
super(context, threadingDomain);
mManagerProxy = null;
mRequest = TimeZoneProviderRequest.createStopUpdatesRequest();
+
+ // A predicate that is used to confirm that an intent service can be used as a
+ // location-based TimeZoneProvider. The service must:
+ // 1) Declare android:permission="android.permission.BIND_TIME_ZONE_PROVIDER_SERVICE" - this
+ // ensures that the provider will only communicate with the system server.
+ // 2) Be in an application that has been granted the
+ // android.permission.INSTALL_LOCATION_TIME_ZONE_PROVIDER_SERVICE permission. This
+ // ensures only trusted time zone providers will be discovered.
+ final String requiredClientPermission = Manifest.permission.BIND_TIME_ZONE_PROVIDER_SERVICE;
+ final String requiredPermission =
+ Manifest.permission.INSTALL_LOCATION_TIME_ZONE_PROVIDER_SERVICE;
+ Predicate<ResolveInfo> intentServiceCheckPredicate = resolveInfo -> {
+ ServiceInfo serviceInfo = resolveInfo.serviceInfo;
+
+ boolean hasClientPermissionRequirement =
+ requiredClientPermission.equals(serviceInfo.permission);
+
+ String packageName = serviceInfo.packageName;
+ PackageManager packageManager = context.getPackageManager();
+ int checkResult = packageManager.checkPermission(requiredPermission, packageName);
+ boolean hasRequiredPermission = checkResult == PERMISSION_GRANTED;
+
+ boolean result = hasClientPermissionRequirement && hasRequiredPermission;
+ if (!result) {
+ warnLog("resolveInfo=" + resolveInfo + " does not meet requirements:"
+ + " hasClientPermissionRequirement=" + hasClientPermissionRequirement
+ + ", hasRequiredPermission=" + hasRequiredPermission);
+ }
+ return result;
+ };
mServiceWatcher = new ServiceWatcher(context, handler, action, this::onBind, this::onUnbind,
- enableOverlayResId, nonOverlayPackageResId);
+ enableOverlayResId, nonOverlayPackageResId, intentServiceCheckPredicate);
}
@Override
diff --git a/services/core/java/com/android/server/net/NetworkPolicyManagerService.java b/services/core/java/com/android/server/net/NetworkPolicyManagerService.java
index 38ffccd..0e7b4b8 100644
--- a/services/core/java/com/android/server/net/NetworkPolicyManagerService.java
+++ b/services/core/java/com/android/server/net/NetworkPolicyManagerService.java
@@ -27,6 +27,8 @@
import static android.Manifest.permission.READ_NETWORK_USAGE_HISTORY;
import static android.Manifest.permission.READ_PHONE_STATE;
import static android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE;
+import static android.app.PendingIntent.FLAG_IMMUTABLE;
+import static android.app.PendingIntent.FLAG_UPDATE_CURRENT;
import static android.content.Intent.ACTION_PACKAGE_ADDED;
import static android.content.Intent.ACTION_UID_REMOVED;
import static android.content.Intent.ACTION_USER_ADDED;
@@ -1429,17 +1431,17 @@
final Intent snoozeIntent = buildSnoozeWarningIntent(policy.template);
builder.setDeleteIntent(PendingIntent.getBroadcast(
- mContext, 0, snoozeIntent, PendingIntent.FLAG_UPDATE_CURRENT));
+ mContext, 0, snoozeIntent, FLAG_UPDATE_CURRENT | FLAG_IMMUTABLE));
final Intent viewIntent = buildViewDataUsageIntent(res, policy.template);
// TODO: Resolve to single code path.
if (UserManager.isHeadlessSystemUserMode()) {
builder.setContentIntent(PendingIntent.getActivityAsUser(
- mContext, 0, viewIntent, PendingIntent.FLAG_UPDATE_CURRENT,
+ mContext, 0, viewIntent, FLAG_UPDATE_CURRENT | FLAG_IMMUTABLE,
/* options= */ null, UserHandle.CURRENT));
} else {
builder.setContentIntent(PendingIntent.getActivity(
- mContext, 0, viewIntent, PendingIntent.FLAG_UPDATE_CURRENT));
+ mContext, 0, viewIntent, FLAG_UPDATE_CURRENT | FLAG_IMMUTABLE));
}
break;
}
@@ -1463,11 +1465,11 @@
// TODO: Resolve to single code path.
if (UserManager.isHeadlessSystemUserMode()) {
builder.setContentIntent(PendingIntent.getActivityAsUser(
- mContext, 0, intent, PendingIntent.FLAG_UPDATE_CURRENT,
+ mContext, 0, intent, FLAG_UPDATE_CURRENT | FLAG_IMMUTABLE,
/* options= */ null, UserHandle.CURRENT));
} else {
builder.setContentIntent(PendingIntent.getActivity(
- mContext, 0, intent, PendingIntent.FLAG_UPDATE_CURRENT));
+ mContext, 0, intent, FLAG_UPDATE_CURRENT | FLAG_IMMUTABLE));
}
break;
}
@@ -1494,11 +1496,11 @@
// TODO: Resolve to single code path.
if (UserManager.isHeadlessSystemUserMode()) {
builder.setContentIntent(PendingIntent.getActivityAsUser(
- mContext, 0, intent, PendingIntent.FLAG_UPDATE_CURRENT,
+ mContext, 0, intent, FLAG_UPDATE_CURRENT | FLAG_IMMUTABLE,
/* options= */ null, UserHandle.CURRENT));
} else {
builder.setContentIntent(PendingIntent.getActivity(
- mContext, 0, intent, PendingIntent.FLAG_UPDATE_CURRENT));
+ mContext, 0, intent, FLAG_UPDATE_CURRENT | FLAG_IMMUTABLE));
}
break;
}
@@ -1515,17 +1517,17 @@
final Intent snoozeIntent = buildSnoozeRapidIntent(policy.template);
builder.setDeleteIntent(PendingIntent.getBroadcast(
- mContext, 0, snoozeIntent, PendingIntent.FLAG_UPDATE_CURRENT));
+ mContext, 0, snoozeIntent, FLAG_UPDATE_CURRENT | FLAG_IMMUTABLE));
final Intent viewIntent = buildViewDataUsageIntent(res, policy.template);
// TODO: Resolve to single code path.
if (UserManager.isHeadlessSystemUserMode()) {
builder.setContentIntent(PendingIntent.getActivityAsUser(
- mContext, 0, viewIntent, PendingIntent.FLAG_UPDATE_CURRENT,
+ mContext, 0, viewIntent, FLAG_UPDATE_CURRENT | FLAG_IMMUTABLE,
/* options= */ null, UserHandle.CURRENT));
} else {
builder.setContentIntent(PendingIntent.getActivity(
- mContext, 0, viewIntent, PendingIntent.FLAG_UPDATE_CURRENT));
+ mContext, 0, viewIntent, FLAG_UPDATE_CURRENT | FLAG_IMMUTABLE));
}
break;
}
diff --git a/services/core/java/com/android/server/notification/ManagedServices.java b/services/core/java/com/android/server/notification/ManagedServices.java
index 54e9b37..21537e6 100644
--- a/services/core/java/com/android/server/notification/ManagedServices.java
+++ b/services/core/java/com/android/server/notification/ManagedServices.java
@@ -73,7 +73,6 @@
import org.xmlpull.v1.XmlPullParser;
import org.xmlpull.v1.XmlPullParserException;
-import org.xmlpull.v1.XmlSerializer;
import java.io.IOException;
import java.io.PrintWriter;
@@ -544,7 +543,8 @@
/**
* This is called to process tags other than {@link #TAG_MANAGED_SERVICES}.
*/
- protected void readExtraTag(String tag, TypedXmlPullParser parser) throws IOException {}
+ protected void readExtraTag(String tag, TypedXmlPullParser parser)
+ throws IOException, XmlPullParserException {}
protected final void migrateToXml() {
for (UserInfo user : mUm.getUsers()) {
@@ -1613,6 +1613,7 @@
public boolean isSystem;
public ServiceConnection connection;
public int targetSdkVersion;
+ public Pair<ComponentName, Integer> mKey;
public ManagedServiceInfo(IInterface service, ComponentName component,
int userid, boolean isSystem, ServiceConnection connection, int targetSdkVersion) {
@@ -1622,6 +1623,7 @@
this.isSystem = isSystem;
this.connection = connection;
this.targetSdkVersion = targetSdkVersion;
+ mKey = Pair.create(component, userid);
}
public boolean isGuest(ManagedServices host) {
diff --git a/services/core/java/com/android/server/notification/NotificationManagerService.java b/services/core/java/com/android/server/notification/NotificationManagerService.java
index c9ed518..c106558 100755
--- a/services/core/java/com/android/server/notification/NotificationManagerService.java
+++ b/services/core/java/com/android/server/notification/NotificationManagerService.java
@@ -66,6 +66,9 @@
import static android.os.IServiceManager.DUMP_FLAG_PRIORITY_NORMAL;
import static android.os.UserHandle.USER_NULL;
import static android.os.UserHandle.USER_SYSTEM;
+import static android.service.notification.NotificationListenerService.FLAG_FILTER_TYPE_ALERTING;
+import static android.service.notification.NotificationListenerService.FLAG_FILTER_TYPE_CONVERSATIONS;
+import static android.service.notification.NotificationListenerService.FLAG_FILTER_TYPE_SILENT;
import static android.service.notification.NotificationListenerService.HINT_HOST_DISABLE_CALL_EFFECTS;
import static android.service.notification.NotificationListenerService.HINT_HOST_DISABLE_EFFECTS;
import static android.service.notification.NotificationListenerService.HINT_HOST_DISABLE_NOTIFICATION_EFFECTS;
@@ -102,6 +105,7 @@
import static com.android.internal.util.FrameworkStatsLog.PACKAGE_NOTIFICATION_CHANNEL_GROUP_PREFERENCES;
import static com.android.internal.util.FrameworkStatsLog.PACKAGE_NOTIFICATION_CHANNEL_PREFERENCES;
import static com.android.internal.util.FrameworkStatsLog.PACKAGE_NOTIFICATION_PREFERENCES;
+import static com.android.internal.util.Preconditions.checkArgument;
import static com.android.server.am.PendingIntentRecord.FLAG_ACTIVITY_SENDER;
import static com.android.server.am.PendingIntentRecord.FLAG_BROADCAST_SENDER;
import static com.android.server.am.PendingIntentRecord.FLAG_SERVICE_SENDER;
@@ -163,6 +167,8 @@
import android.content.pm.PackageManager.NameNotFoundException;
import android.content.pm.PackageManagerInternal;
import android.content.pm.ParceledListSlice;
+import android.content.pm.ResolveInfo;
+import android.content.pm.ServiceInfo;
import android.content.pm.ShortcutInfo;
import android.content.pm.ShortcutServiceInternal;
import android.content.pm.UserInfo;
@@ -209,6 +215,7 @@
import android.service.notification.IStatusBarNotificationHolder;
import android.service.notification.ListenersDisablingEffectsProto;
import android.service.notification.NotificationAssistantService;
+import android.service.notification.NotificationListenerFilter;
import android.service.notification.NotificationListenerService;
import android.service.notification.NotificationRankingUpdate;
import android.service.notification.NotificationRecordProto;
@@ -301,6 +308,7 @@
import java.time.Duration;
import java.util.ArrayList;
import java.util.Arrays;
+import java.util.Collection;
import java.util.HashSet;
import java.util.Iterator;
import java.util.LinkedList;
@@ -1021,7 +1029,7 @@
nv.recycle();
}
reportUserInteraction(r);
- mAssistants.notifyAssistantActionClicked(r.getSbn(), action, generatedByAssistant);
+ mAssistants.notifyAssistantActionClicked(r, action, generatedByAssistant);
}
}
@@ -1110,7 +1118,7 @@
reportSeen(r);
}
r.setVisibility(true, nv.rank, nv.count, mNotificationRecordLogger);
- mAssistants.notifyAssistantVisibilityChangedLocked(r.getSbn(), true);
+ mAssistants.notifyAssistantVisibilityChangedLocked(r, true);
boolean isHun = (nv.location
== NotificationVisibility.NotificationLocation.LOCATION_FIRST_HEADS_UP);
// hasBeenVisiblyExpanded must be called after updating the expansion state of
@@ -1129,7 +1137,7 @@
NotificationRecord r = mNotificationsByKey.get(nv.key);
if (r == null) continue;
r.setVisibility(false, nv.rank, nv.count, mNotificationRecordLogger);
- mAssistants.notifyAssistantVisibilityChangedLocked(r.getSbn(), false);
+ mAssistants.notifyAssistantVisibilityChangedLocked(r, false);
nv.recycle();
}
}
@@ -1161,7 +1169,7 @@
reportUserInteraction(r);
}
mAssistants.notifyAssistantExpansionChangedLocked(
- r.getSbn(), userAction, expanded);
+ r.getSbn(), r.getNotificationType(), userAction, expanded);
}
}
}
@@ -1180,7 +1188,7 @@
NotificationRecordLogger.NotificationEvent.NOTIFICATION_DIRECT_REPLIED,
r);
reportUserInteraction(r);
- mAssistants.notifyAssistantNotificationDirectReplyLocked(r.getSbn());
+ mAssistants.notifyAssistantNotificationDirectReplyLocked(r);
}
}
}
@@ -1227,7 +1235,8 @@
// Treat clicking on a smart reply as a user interaction.
reportUserInteraction(r);
mAssistants.notifyAssistantSuggestedReplySent(
- r.getSbn(), reply, r.getSuggestionsGeneratedByAssistant());
+ r.getSbn(), r.getNotificationType(), reply,
+ r.getSuggestionsGeneratedByAssistant());
}
}
}
@@ -2241,7 +2250,8 @@
init(handler, new RankingHandlerWorker(mRankingThread.getLooper()),
AppGlobals.getPackageManager(), getContext().getPackageManager(),
getLocalService(LightsManager.class),
- new NotificationListeners(AppGlobals.getPackageManager()),
+ new NotificationListeners(getContext(), mNotificationLock, mUserProfiles,
+ AppGlobals.getPackageManager()),
new NotificationAssistants(getContext(), mNotificationLock, mUserProfiles,
AppGlobals.getPackageManager()),
new ConditionProviders(getContext(), mUserProfiles, AppGlobals.getPackageManager()),
@@ -3253,6 +3263,21 @@
}
@Override
+ public NotificationListenerFilter getListenerFilter(ComponentName cn, int userId) {
+ checkCallerIsSystem();
+ return mListeners.getNotificationListenerFilter(Pair.create(cn, userId));
+ }
+
+ @Override
+ public void setListenerFilter(ComponentName cn, int userId,
+ NotificationListenerFilter nlf) {
+ checkCallerIsSystem();
+ mListeners.setNotificationListenerFilter(Pair.create(cn, userId), nlf);
+ // TODO (b/173052211): cancel notifications for listeners that can no longer see them
+ handleSavePolicyFile();
+ }
+
+ @Override
public int getPackageImportance(String pkg) {
checkCallerIsSystemOrSameApp(pkg);
return mPreferencesHelper.getImportance(pkg, Binder.getCallingUid());
@@ -4268,7 +4293,7 @@
: mNotificationList.get(i);
if (r == null) continue;
StatusBarNotification sbn = r.getSbn();
- if (!isVisibleToListener(sbn, info)) continue;
+ if (!isVisibleToListener(sbn, r.getNotificationType(), info)) continue;
StatusBarNotification sbnToSend =
(trim == TRIM_FULL) ? sbn : sbn.cloneLight();
list.add(sbnToSend);
@@ -4298,7 +4323,7 @@
final NotificationRecord r = snoozedRecords.get(i);
if (r == null) continue;
StatusBarNotification sbn = r.getSbn();
- if (!isVisibleToListener(sbn, info)) continue;
+ if (!isVisibleToListener(sbn, r.getNotificationType(), info)) continue;
StatusBarNotification sbnToSend =
(trim == TRIM_FULL) ? sbn : sbn.cloneLight();
list.add(sbnToSend);
@@ -6339,7 +6364,7 @@
cancelNotificationLocked(r, false, REASON_SNOOZED, wasPosted, null);
updateLightsLocked();
if (mSnoozeCriterionId != null) {
- mAssistants.notifyAssistantSnoozedLocked(r.getSbn(), mSnoozeCriterionId);
+ mAssistants.notifyAssistantSnoozedLocked(r, mSnoozeCriterionId);
mSnoozeHelper.snooze(r, mSnoozeCriterionId);
} else {
mSnoozeHelper.snooze(r, mDuration);
@@ -8812,7 +8837,7 @@
for (int i = 0; i < N; i++) {
NotificationRecord record = mNotificationList.get(i);
- if (!isVisibleToListener(record.getSbn(), info)) {
+ if (!isVisibleToListener(record.getSbn(), record.getNotificationType(), info)) {
continue;
}
final String key = record.getSbn().getKey();
@@ -8886,11 +8911,21 @@
}
@VisibleForTesting
- boolean isVisibleToListener(StatusBarNotification sbn, ManagedServiceInfo listener) {
+ boolean isVisibleToListener(StatusBarNotification sbn, int notificationType,
+ ManagedServiceInfo listener) {
if (!listener.enabledAndUserMatches(sbn.getUserId())) {
return false;
}
- return isInteractionVisibleToListener(listener, sbn.getUserId());
+ if (!isInteractionVisibleToListener(listener, sbn.getUserId())) {
+ return false;
+ }
+ NotificationListenerFilter nls = mListeners.getNotificationListenerFilter(listener.mKey);
+ if (nls != null
+ && (!nls.isTypeAllowed(notificationType)
+ || !nls.isPackageAllowed(sbn.getPackageName()))) {
+ return false;
+ }
+ return true;
}
/**
@@ -9126,7 +9161,8 @@
for (final ManagedServiceInfo info : NotificationAssistants.this.getServices()) {
ArrayList<String> keys = new ArrayList<>(records.size());
for (NotificationRecord r : records) {
- boolean sbnVisible = isVisibleToListener(r.getSbn(), info)
+ boolean sbnVisible = isVisibleToListener(
+ r.getSbn(), r.getNotificationType(), info)
&& info.isSameUser(r.getUserId());
if (sbnVisible) {
keys.add(r.getKey());
@@ -9241,6 +9277,7 @@
final StatusBarNotification sbn = r.getSbn();
notifyAssistantLocked(
sbn,
+ r.getNotificationType(),
true /* sameUserOnly */,
(assistant, sbnHolder) -> {
try {
@@ -9257,14 +9294,15 @@
@GuardedBy("mNotificationLock")
void notifyAssistantVisibilityChangedLocked(
- final StatusBarNotification sbn,
+ final NotificationRecord r,
final boolean isVisible) {
- final String key = sbn.getKey();
+ final String key = r.getSbn().getKey();
if (DBG) {
Slog.d(TAG, "notifyAssistantVisibilityChangedLocked: " + key);
}
notifyAssistantLocked(
- sbn,
+ r.getSbn(),
+ r.getNotificationType(),
true /* sameUserOnly */,
(assistant, sbnHolder) -> {
try {
@@ -9278,11 +9316,13 @@
@GuardedBy("mNotificationLock")
void notifyAssistantExpansionChangedLocked(
final StatusBarNotification sbn,
+ final int notificationType,
final boolean isUserAction,
final boolean isExpanded) {
final String key = sbn.getKey();
notifyAssistantLocked(
sbn,
+ notificationType,
true /* sameUserOnly */,
(assistant, sbnHolder) -> {
try {
@@ -9295,10 +9335,11 @@
@GuardedBy("mNotificationLock")
void notifyAssistantNotificationDirectReplyLocked(
- final StatusBarNotification sbn) {
- final String key = sbn.getKey();
+ final NotificationRecord r) {
+ final String key = r.getKey();
notifyAssistantLocked(
- sbn,
+ r.getSbn(),
+ r.getNotificationType(),
true /* sameUserOnly */,
(assistant, sbnHolder) -> {
try {
@@ -9311,10 +9352,12 @@
@GuardedBy("mNotificationLock")
void notifyAssistantSuggestedReplySent(
- final StatusBarNotification sbn, CharSequence reply, boolean generatedByAssistant) {
+ final StatusBarNotification sbn, int notificationType,
+ CharSequence reply, boolean generatedByAssistant) {
final String key = sbn.getKey();
notifyAssistantLocked(
sbn,
+ notificationType,
true /* sameUserOnly */,
(assistant, sbnHolder) -> {
try {
@@ -9332,11 +9375,12 @@
@GuardedBy("mNotificationLock")
void notifyAssistantActionClicked(
- final StatusBarNotification sbn, Notification.Action action,
+ final NotificationRecord r, Notification.Action action,
boolean generatedByAssistant) {
- final String key = sbn.getKey();
+ final String key = r.getSbn().getKey();
notifyAssistantLocked(
- sbn,
+ r.getSbn(),
+ r.getNotificationType(),
true /* sameUserOnly */,
(assistant, sbnHolder) -> {
try {
@@ -9358,9 +9402,10 @@
*/
@GuardedBy("mNotificationLock")
private void notifyAssistantSnoozedLocked(
- final StatusBarNotification sbn, final String snoozeCriterionId) {
+ final NotificationRecord r, final String snoozeCriterionId) {
notifyAssistantLocked(
- sbn,
+ r.getSbn(),
+ r.getNotificationType(),
true /* sameUserOnly */,
(assistant, sbnHolder) -> {
try {
@@ -9384,6 +9429,7 @@
@GuardedBy("mNotificationLock")
private void notifyAssistantLocked(
final StatusBarNotification sbn,
+ int notificationType,
boolean sameUserOnly,
BiConsumer<INotificationListener, StatusBarNotificationHolder> callback) {
TrimCache trimCache = new TrimCache(sbn);
@@ -9397,7 +9443,7 @@
+ sameUserOnly + "], callback = [" + callback + "]");
}
for (final ManagedServiceInfo info : NotificationAssistants.this.getServices()) {
- boolean sbnVisible = isVisibleToListener(sbn, info)
+ boolean sbnVisible = isVisibleToListener(sbn, notificationType, info)
&& (!sameUserOnly || info.isSameUser(sbn.getUserId()));
if (debug) {
Slog.v(TAG, "notifyAssistantLocked info=" + info + " snbVisible=" + sbnVisible);
@@ -9451,11 +9497,22 @@
public class NotificationListeners extends ManagedServices {
static final String TAG_ENABLED_NOTIFICATION_LISTENERS = "enabled_listeners";
+ static final String TAG_REQUESTED_LISTENERS = "requested_listeners";
+ static final String TAG_REQUESTED_LISTENER = "listener";
+ static final String ATT_COMPONENT = "component";
+ static final String ATT_TYPES = "types";
+ static final String ATT_PKGS = "pkgs";
+ static final String TAG_APPROVED = "allowed";
+ static final String TAG_DISALLOWED= "disallowed";
+ static final String XML_SEPARATOR = ",";
private final ArraySet<ManagedServiceInfo> mLightTrimListeners = new ArraySet<>();
+ ArrayMap<Pair<ComponentName, Integer>, NotificationListenerFilter>
+ mRequestedNotificationListeners = new ArrayMap<>();
- public NotificationListeners(IPackageManager pm) {
- super(getContext(), mNotificationLock, mUserProfiles, pm);
+ public NotificationListeners(Context context, Object lock, UserProfiles userProfiles,
+ IPackageManager pm) {
+ super(context, lock, userProfiles, pm);
}
@Override
@@ -9552,6 +9609,59 @@
}
@Override
+ public void onUserRemoved(int user) {
+ super.onUserRemoved(user);
+ for (int i = mRequestedNotificationListeners.size() - 1; i >= 0; i--) {
+ if (mRequestedNotificationListeners.keyAt(i).second == user) {
+ mRequestedNotificationListeners.removeAt(i);
+ }
+ }
+ }
+
+ @Override
+ public void onUserUnlocked(int user) {
+ int flags = PackageManager.GET_SERVICES | PackageManager.GET_META_DATA;
+
+ final PackageManager pmWrapper = mContext.getPackageManager();
+ List<ResolveInfo> installedServices = pmWrapper.queryIntentServicesAsUser(
+ new Intent(getConfig().serviceInterface), flags, user);
+
+ for (ResolveInfo resolveInfo : installedServices) {
+ ServiceInfo info = resolveInfo.serviceInfo;
+
+ if (!getConfig().bindPermission.equals(info.permission)) {
+ continue;
+ }
+ Pair key = Pair.create(info.getComponentName(), user);
+ if (!mRequestedNotificationListeners.containsKey(key)) {
+ mRequestedNotificationListeners.put(key, new NotificationListenerFilter());
+ }
+ }
+ super.onUserUnlocked(user);
+ }
+
+ @Override
+ public void onPackagesChanged(boolean removingPackage, String[] pkgList, int[] uidList) {
+ super.onPackagesChanged(removingPackage, pkgList, uidList);
+
+ // Since the default behavior is to allow everything, we don't need to explicitly
+ // handle package add or update. they will be added to the xml file on next boot or
+ // when the user tries to change the settings.
+ if (removingPackage) {
+ for (int i = 0; i < pkgList.length; i++) {
+ String pkg = pkgList[i];
+ int userId = UserHandle.getUserId(uidList[i]);
+ for (int j = mRequestedNotificationListeners.size() - 1; j >= 0; j--) {
+ Pair<ComponentName, Integer> key = mRequestedNotificationListeners.keyAt(j);
+ if (key.second == userId && key.first.getPackageName().equals(pkg)) {
+ mRequestedNotificationListeners.removeAt(j);
+ }
+ }
+ }
+ }
+ }
+
+ @Override
protected String getRequiredPermission() {
return null;
}
@@ -9563,6 +9673,75 @@
return true;
}
+ @Override
+ protected void readExtraTag(String tag, TypedXmlPullParser parser)
+ throws IOException, XmlPullParserException {
+ if (TAG_REQUESTED_LISTENERS.equals(tag)) {
+ final int listenersOuterDepth = parser.getDepth();
+ while (XmlUtils.nextElementWithin(parser, listenersOuterDepth)) {
+ if (!TAG_REQUESTED_LISTENER.equals(parser.getName())) {
+ continue;
+ }
+ final int userId = XmlUtils.readIntAttribute(parser, ATT_USER_ID);
+ final ComponentName cn = ComponentName.unflattenFromString(
+ XmlUtils.readStringAttribute(parser, ATT_COMPONENT));
+ int approved = FLAG_FILTER_TYPE_CONVERSATIONS | FLAG_FILTER_TYPE_ALERTING
+ | FLAG_FILTER_TYPE_SILENT;
+
+ ArraySet<String> disallowedPkgs = new ArraySet<>();
+ final int listenerOuterDepth = parser.getDepth();
+ while (XmlUtils.nextElementWithin(parser, listenerOuterDepth)) {
+ if (TAG_APPROVED.equals(parser.getName())) {
+ approved = XmlUtils.readIntAttribute(parser, ATT_TYPES);
+ } else if (TAG_DISALLOWED.equals(parser.getName())) {
+ String pkgs = XmlUtils.readStringAttribute(parser, ATT_PKGS);
+ if (!TextUtils.isEmpty(pkgs)) {
+ disallowedPkgs = new ArraySet<>(pkgs.split(XML_SEPARATOR));
+ }
+ }
+ }
+ NotificationListenerFilter nlf =
+ new NotificationListenerFilter(approved, disallowedPkgs);
+ mRequestedNotificationListeners.put(Pair.create(cn, userId), nlf);
+ }
+ }
+ }
+
+ @Override
+ protected void writeExtraXmlTags(TypedXmlSerializer out) throws IOException {
+ out.startTag(null, TAG_REQUESTED_LISTENERS);
+ for (Pair<ComponentName, Integer> listener : mRequestedNotificationListeners.keySet()) {
+ NotificationListenerFilter nlf = mRequestedNotificationListeners.get(listener);
+ out.startTag(null, TAG_REQUESTED_LISTENER);
+ XmlUtils.writeStringAttribute(
+ out, ATT_COMPONENT, listener.first.flattenToString());
+ XmlUtils.writeIntAttribute(out, ATT_USER_ID, listener.second);
+
+ out.startTag(null, TAG_APPROVED);
+ XmlUtils.writeIntAttribute(out, ATT_TYPES, nlf.getTypes());
+ out.endTag(null, TAG_APPROVED);
+
+ out.startTag(null, TAG_DISALLOWED);
+ XmlUtils.writeStringAttribute(
+ out, ATT_PKGS, String.join(XML_SEPARATOR, nlf.getDisallowedPackages()));
+ out.endTag(null, TAG_DISALLOWED);
+
+ out.endTag(null, TAG_REQUESTED_LISTENER);
+ }
+
+ out.endTag(null, TAG_REQUESTED_LISTENERS);
+ }
+
+ protected @Nullable NotificationListenerFilter getNotificationListenerFilter(
+ Pair<ComponentName, Integer> pair) {
+ return mRequestedNotificationListeners.get(pair);
+ }
+
+ protected void setNotificationListenerFilter(Pair<ComponentName, Integer> pair,
+ NotificationListenerFilter nlf) {
+ mRequestedNotificationListeners.put(pair, nlf);
+ }
+
@GuardedBy("mNotificationLock")
public void setOnNotificationPostedTrimLocked(ManagedServiceInfo info, int trim) {
if (trim == TRIM_LIGHT) {
@@ -9618,8 +9797,9 @@
TrimCache trimCache = new TrimCache(sbn);
for (final ManagedServiceInfo info : getServices()) {
- boolean sbnVisible = isVisibleToListener(sbn, info);
- boolean oldSbnVisible = (oldSbn != null) && isVisibleToListener(oldSbn, info);
+ boolean sbnVisible = isVisibleToListener(sbn, r. getNotificationType(), info);
+ boolean oldSbnVisible = (oldSbn != null)
+ && isVisibleToListener(oldSbn, old.getNotificationType(), info);
// This notification hasn't been and still isn't visible -> ignore.
if (!oldSbnVisible && !sbnVisible) {
continue;
@@ -9672,7 +9852,7 @@
for (final NotificationRecord r : mNotificationList) {
// When granting permissions, ignore notifications which are invisible.
// When revoking permissions, all notifications are invisible, so process all.
- if (grant && !isVisibleToListener(r.getSbn(), info)) {
+ if (grant && !isVisibleToListener(r.getSbn(), r.getNotificationType(), info)) {
continue;
}
// If the notification is hidden, permissions are not required by the listener.
@@ -9714,7 +9894,7 @@
// notification
final StatusBarNotification sbnLight = sbn.cloneLight();
for (final ManagedServiceInfo info : getServices()) {
- if (!isVisibleToListener(sbn, info)) {
+ if (!isVisibleToListener(sbn, r.getNotificationType(), info)) {
continue;
}
@@ -9754,7 +9934,8 @@
public void notifyRankingUpdateLocked(List<NotificationRecord> changedHiddenNotifications) {
boolean isHiddenRankingUpdate = changedHiddenNotifications != null
&& changedHiddenNotifications.size() > 0;
-
+ // TODO (b/73052211): if the ranking update changed the notification type,
+ // cancel notifications for NLSes that can't see them anymore
for (final ManagedServiceInfo serviceInfo : getServices()) {
if (!serviceInfo.isEnabledForCurrentProfiles() || !isInteractionVisibleToListener(
serviceInfo, ActivityManager.getCurrentUser())) {
@@ -9765,7 +9946,8 @@
if (isHiddenRankingUpdate && serviceInfo.targetSdkVersion >=
Build.VERSION_CODES.P) {
for (NotificationRecord rec : changedHiddenNotifications) {
- if (isVisibleToListener(rec.getSbn(), serviceInfo)) {
+ if (isVisibleToListener(
+ rec.getSbn(), rec.getNotificationType(), serviceInfo)) {
notifyThisListener = true;
break;
}
@@ -9979,6 +10161,7 @@
}
}
+
class RoleObserver implements OnRoleHoldersChangedListener {
// Role name : user id : list of approved packages
private ArrayMap<String, ArrayMap<Integer, ArraySet<String>>> mNonBlockableDefaultApps;
@@ -10233,12 +10416,15 @@
private final Set<String> mPackagesShown = new ArraySet<>();
@Override
- public IBinder getToken() {
- return ALLOWLIST_TOKEN;
- }
-
- @Override
- public boolean isActivityStartAllowed(int uid, String packageName) {
+ public boolean isActivityStartAllowed(Collection<IBinder> tokens, int uid,
+ String packageName) {
+ checkArgument(!tokens.isEmpty());
+ for (IBinder token : tokens) {
+ if (token != ALLOWLIST_TOKEN) {
+ // We only block or warn if the start is exclusively due to notification
+ return true;
+ }
+ }
String toastMessage = "Indirect activity start from " + packageName;
String logcatMessage =
"Indirect notification activity start (trampoline) from " + packageName;
@@ -10256,6 +10442,15 @@
}
}
+ @Override
+ public boolean canCloseSystemDialogs(Collection<IBinder> tokens, int uid) {
+ // If the start is allowed via notification, we allow the app to close system dialogs
+ // only if their targetSdk < S, otherwise they have no valid reason to do this since
+ // trampolines are blocked.
+ return tokens.contains(ALLOWLIST_TOKEN)
+ && !CompatChanges.isChangeEnabled(NOTIFICATION_TRAMPOLINE_BLOCK, uid);
+ }
+
private void toast(String message) {
mUiHandler.post(() ->
Toast.makeText(getUiContext(), message + "\nSee go/s-trampolines.",
diff --git a/services/core/java/com/android/server/notification/NotificationRecord.java b/services/core/java/com/android/server/notification/NotificationRecord.java
index cff4f07..6bc4f7e 100644
--- a/services/core/java/com/android/server/notification/NotificationRecord.java
+++ b/services/core/java/com/android/server/notification/NotificationRecord.java
@@ -1257,6 +1257,16 @@
return !Objects.equals(getSbn().getPackageName(), getSbn().getOpPkg());
}
+ public int getNotificationType() {
+ if (isConversation()) {
+ return NotificationListenerService.FLAG_FILTER_TYPE_CONVERSATIONS;
+ } else if (getImportance() >= IMPORTANCE_DEFAULT) {
+ return NotificationListenerService.FLAG_FILTER_TYPE_ALERTING;
+ } else {
+ return NotificationListenerService.FLAG_FILTER_TYPE_SILENT;
+ }
+ }
+
/**
* @return all {@link Uri} that should have permission granted to whoever
* will be rendering it. This list has already been vetted to only
diff --git a/services/core/java/com/android/server/notification/ZenModeHelper.java b/services/core/java/com/android/server/notification/ZenModeHelper.java
index 5cd22e0..de77372 100644
--- a/services/core/java/com/android/server/notification/ZenModeHelper.java
+++ b/services/core/java/com/android/server/notification/ZenModeHelper.java
@@ -88,7 +88,6 @@
import org.xmlpull.v1.XmlPullParser;
import org.xmlpull.v1.XmlPullParserException;
-import org.xmlpull.v1.XmlSerializer;
import java.io.IOException;
import java.io.PrintWriter;
@@ -106,6 +105,9 @@
// The amount of time rules instances can exist without their owning app being installed.
private static final int RULE_INSTANCE_GRACE_PERIOD = 1000 * 60 * 60 * 72;
+ // pkg|userId => uid
+ protected final ArrayMap<String, Integer> mRulesUidCache = new ArrayMap<>();
+
private final Context mContext;
private final H mHandler;
private final SettingsObserver mSettingsObserver;
@@ -145,7 +147,7 @@
mHandler = new H(looper);
addCallback(mMetrics);
mAppOps = context.getSystemService(AppOpsManager.class);
- mNotificationManager = context.getSystemService(NotificationManager.class);
+ mNotificationManager = context.getSystemService(NotificationManager.class);
mDefaultConfig = readDefaultConfig(mContext.getResources());
updateDefaultAutomaticRuleNames();
@@ -384,17 +386,25 @@
synchronized (mConfig) {
if (mConfig == null) return false;
newConfig = mConfig.copy();
- ZenRule rule = newConfig.automaticRules.get(id);
- if (rule == null) return false;
- if (canManageAutomaticZenRule(rule)) {
+ ZenRule ruleToRemove = newConfig.automaticRules.get(id);
+ if (ruleToRemove == null) return false;
+ if (canManageAutomaticZenRule(ruleToRemove)) {
newConfig.automaticRules.remove(id);
+ if (ruleToRemove.pkg != null && !"android".equals(ruleToRemove.pkg)) {
+ for (ZenRule currRule : newConfig.automaticRules.values()) {
+ if (currRule.pkg != null && currRule.pkg.equals(ruleToRemove.pkg)) {
+ break; // no need to remove from cache
+ }
+ }
+ mRulesUidCache.remove(getPackageUserKey(ruleToRemove.pkg, newConfig.user));
+ }
if (DEBUG) Log.d(TAG, "removeZenRule zenRule=" + id + " reason=" + reason);
} else {
throw new SecurityException(
"Cannot delete rules not owned by your condition provider");
}
dispatchOnAutomaticRuleStatusChanged(
- mConfig.user, rule.pkg, id, AUTOMATIC_RULE_STATUS_REMOVED);
+ mConfig.user, ruleToRemove.pkg, id, AUTOMATIC_RULE_STATUS_REMOVED);
return setConfigLocked(newConfig, reason, null, true);
}
}
@@ -1192,7 +1202,6 @@
public void pullRules(List<StatsEvent> events) {
synchronized (mConfig) {
final int numConfigs = mConfigs.size();
- int id = 0;
for (int i = 0; i < numConfigs; i++) {
final int user = mConfigs.keyAt(i);
final ZenModeConfig config = mConfigs.valueAt(i);
@@ -1208,16 +1217,16 @@
.writeByteArray(config.toZenPolicy().toProto());
events.add(data.build());
if (config.manualRule != null && config.manualRule.enabler != null) {
- ruleToProto(user, config.manualRule, events);
+ ruleToProtoLocked(user, config.manualRule, events);
}
for (ZenRule rule : config.automaticRules.values()) {
- ruleToProto(user, rule, events);
+ ruleToProtoLocked(user, rule, events);
}
}
}
}
- private void ruleToProto(int user, ZenRule rule, List<StatsEvent> events) {
+ private void ruleToProtoLocked(int user, ZenRule rule, List<StatsEvent> events) {
// Make the ID safe.
String id = rule.id == null ? "" : rule.id;
if (!ZenModeConfig.DEFAULT_RULE_IDS.contains(id)) {
@@ -1231,9 +1240,6 @@
id = ZenModeConfig.MANUAL_RULE_ID;
}
- // TODO: fetch the uid from the package manager
- int uid = "android".equals(pkg) ? Process.SYSTEM_UID : 0;
-
SysUiStatsEvent.Builder data;
data = mStatsEventBuilderFactory.newBuilder()
.setAtomId(DND_MODE_RULE)
@@ -1242,7 +1248,7 @@
.writeBoolean(false) // channels_bypassing unused for rules
.writeInt(rule.zenMode)
.writeString(id)
- .writeInt(uid)
+ .writeInt(getPackageUid(pkg, user))
.addBooleanAnnotation(ANNOTATION_ID_IS_UID, true);
byte[] policyProto = new byte[]{};
if (rule.zenPolicy != null) {
@@ -1252,6 +1258,24 @@
events.add(data.build());
}
+ private int getPackageUid(String pkg, int user) {
+ if ("android".equals(pkg)) {
+ return Process.SYSTEM_UID;
+ }
+ final String key = getPackageUserKey(pkg, user);
+ if (mRulesUidCache.get(key) == null) {
+ try {
+ mRulesUidCache.put(key, mPm.getPackageUidAsUser(pkg, user));
+ } catch (PackageManager.NameNotFoundException e) {
+ }
+ }
+ return mRulesUidCache.getOrDefault(key, -1);
+ }
+
+ private static String getPackageUserKey(String pkg, int user) {
+ return pkg + "|" + user;
+ }
+
@VisibleForTesting
protected final class RingerModeDelegate implements AudioManagerInternal.RingerModeDelegate {
@Override
diff --git a/services/core/java/com/android/server/wm/ActivityClientController.java b/services/core/java/com/android/server/wm/ActivityClientController.java
index a61e08a..c25f1b4 100644
--- a/services/core/java/com/android/server/wm/ActivityClientController.java
+++ b/services/core/java/com/android/server/wm/ActivityClientController.java
@@ -30,7 +30,6 @@
import static com.android.internal.protolog.ProtoLogGroup.WM_DEBUG_IMMERSIVE;
import static com.android.server.wm.ActivityTaskManagerDebugConfig.DEBUG_ALL;
import static com.android.server.wm.ActivityTaskManagerDebugConfig.DEBUG_SWITCH;
-import static com.android.server.wm.ActivityTaskManagerDebugConfig.POSTFIX_VISIBILITY;
import static com.android.server.wm.ActivityTaskManagerDebugConfig.TAG_ATM;
import static com.android.server.wm.ActivityTaskManagerDebugConfig.TAG_WITH_CLASS_NAME;
import static com.android.server.wm.ActivityTaskManagerService.RELAUNCH_REASON_NONE;
@@ -42,7 +41,6 @@
import android.annotation.NonNull;
import android.app.Activity;
import android.app.ActivityManager;
-import android.app.ActivityOptions;
import android.app.ActivityTaskManager;
import android.app.IActivityClientController;
import android.app.PictureInPictureParams;
@@ -80,7 +78,6 @@
*/
class ActivityClientController extends IActivityClientController.Stub {
private static final String TAG = TAG_WITH_CLASS_NAME ? "ActivityClientController" : TAG_ATM;
- private static final String TAG_VISIBILITY = TAG + POSTFIX_VISIBILITY;
private final ActivityTaskManagerService mService;
private final WindowManagerGlobalLock mGlobalLock;
@@ -557,23 +554,6 @@
}
@Override
- public Bundle getActivityOptions(IBinder token) {
- final long origId = Binder.clearCallingIdentity();
- try {
- synchronized (mGlobalLock) {
- final ActivityRecord r = ActivityRecord.isInRootTaskLocked(token);
- if (r == null) {
- return null;
- }
- final ActivityOptions activityOptions = r.takeOptionsLocked(true /* fromClient */);
- return activityOptions != null ? activityOptions.toBundle() : null;
- }
- } finally {
- Binder.restoreCallingIdentity(origId);
- }
- }
-
- @Override
public void setRequestedOrientation(IBinder token, int requestedOrientation) {
final long origId = Binder.clearCallingIdentity();
try {
diff --git a/services/core/java/com/android/server/wm/ActivityRecord.java b/services/core/java/com/android/server/wm/ActivityRecord.java
index ef845c8..c9d8eef 100644
--- a/services/core/java/com/android/server/wm/ActivityRecord.java
+++ b/services/core/java/com/android/server/wm/ActivityRecord.java
@@ -284,6 +284,7 @@
import android.view.IAppTransitionAnimationSpecsFuture;
import android.view.IApplicationToken;
import android.view.InputApplicationHandle;
+import android.view.RemoteAnimationAdapter;
import android.view.RemoteAnimationDefinition;
import android.view.RemoteAnimationTarget;
import android.view.SurfaceControl;
@@ -462,7 +463,10 @@
HashSet<WeakReference<PendingIntentRecord>> pendingResults; // all pending intents for this act
ArrayList<ReferrerIntent> newIntents; // any pending new intents for single-top mode
Intent mLastNewIntent; // the last new intent we delivered to client
- ActivityOptions pendingOptions; // most recently given options
+ /** The most recently given options. */
+ private ActivityOptions mPendingOptions;
+ /** Non-null if {@link #mPendingOptions} specifies the remote animation. */
+ private RemoteAnimationAdapter mPendingRemoteAnimation;
ActivityOptions returningOptions; // options that are coming back via convertToTranslucent
AppTimeTracker appTimeTracker; // set if we are tracking the time in this app/task/activity
ActivityServiceConnectionsHolder mServiceConnectionsHolder; // Service connections.
@@ -882,8 +886,13 @@
}
}
}
- if (pendingOptions != null) {
- pw.print(prefix); pw.print("pendingOptions="); pw.println(pendingOptions);
+ if (mPendingOptions != null) {
+ pw.print(prefix); pw.print("pendingOptions="); pw.println(mPendingOptions);
+ }
+ if (mPendingRemoteAnimation != null) {
+ pw.print(prefix);
+ pw.print("pendingRemoteAnimationCallingPid=");
+ pw.println(mPendingRemoteAnimation.getCallingPid());
}
if (appTimeTracker != null) {
appTimeTracker.dumpWithHeader(pw, prefix, false);
@@ -1009,9 +1018,8 @@
if (info.minAspectRatio != 0) {
pw.println(prefix + "minAspectRatio=" + info.minAspectRatio);
}
- if (info.supportsSizeChanges) {
- pw.println(prefix + "supportsSizeChanges=true");
- }
+ pw.println(prefix + "supportsSizeChanges="
+ + ActivityInfo.sizeChangesSupportModeToString(info.supportsSizeChanges()));
if (info.configChanges != 0) {
pw.println(prefix + "configChanges=0x" + Integer.toHexString(info.configChanges));
}
@@ -1633,8 +1641,8 @@
lockTaskLaunchMode = getLockTaskLaunchMode(aInfo, options);
if (options != null) {
- pendingOptions = options;
- final PendingIntent usageReport = pendingOptions.getUsageTimeReport();
+ setOptions(options);
+ final PendingIntent usageReport = options.getUsageTimeReport();
if (usageReport != null) {
appTimeTracker = new AppTimeTracker(usageReport);
}
@@ -2206,7 +2214,7 @@
if (task != null && !finishing) {
task = null;
}
- clearOptionsLocked();
+ abortAndClearOptionsAnimation();
}
}
@@ -2993,7 +3001,7 @@
}
finishing = true;
if (stopped) {
- clearOptionsLocked();
+ abortAndClearOptionsAnimation();
}
mAtmService.getTransitionController().requestTransitionIfNeeded(TRANSIT_CLOSE, this);
}
@@ -3861,33 +3869,47 @@
void updateOptionsLocked(ActivityOptions options) {
if (options != null) {
if (DEBUG_TRANSITION) Slog.i(TAG, "Update options for " + this);
- if (pendingOptions != null) {
- pendingOptions.abort();
+ if (mPendingOptions != null) {
+ mPendingOptions.abort();
}
- pendingOptions = options;
+ setOptions(options);
}
}
- void applyOptionsLocked() {
- if (pendingOptions != null
- && pendingOptions.getAnimationType() != ANIM_SCENE_TRANSITION) {
- if (DEBUG_TRANSITION) Slog.i(TAG, "Applying options for " + this);
- applyOptionsLocked(pendingOptions, intent);
- if (task == null) {
- clearOptionsLocked(false /* withAbort */);
- } else {
- // This will clear the options for all the ActivityRecords for this Task.
- task.forAllActivities((r) -> {
- r.clearOptionsLocked(false /* withAbort */);
- });
+ private void setOptions(@NonNull ActivityOptions options) {
+ mPendingOptions = options;
+ if (options.getAnimationType() == ANIM_REMOTE_ANIMATION) {
+ mPendingRemoteAnimation = options.getRemoteAnimationAdapter();
+ }
+ }
+
+ void applyOptionsAnimation() {
+ if (DEBUG_TRANSITION) Slog.i(TAG, "Applying options for " + this);
+ if (mPendingRemoteAnimation != null) {
+ mDisplayContent.mAppTransition.overridePendingAppTransitionRemote(
+ mPendingRemoteAnimation);
+ } else {
+ if (mPendingOptions == null
+ || mPendingOptions.getAnimationType() == ANIM_SCENE_TRANSITION) {
+ // Scene transition will run on the client side.
+ return;
}
+ applyOptionsAnimation(mPendingOptions, intent);
+ }
+ if (task == null) {
+ clearOptionsAnimation();
+ } else {
+ // This will clear the options for all the ActivityRecords for this Task.
+ task.forAllActivities((r) -> {
+ r.clearOptionsAnimation();
+ });
}
}
/**
* Apply override app transition base on options & animation type.
*/
- void applyOptionsLocked(ActivityOptions pendingOptions, Intent intent) {
+ private void applyOptionsAnimation(ActivityOptions pendingOptions, Intent intent) {
final int animationType = pendingOptions.getAnimationType();
final DisplayContent displayContent = getDisplayContent();
switch (animationType) {
@@ -3969,10 +3991,6 @@
displayContent.mAppTransition
.overridePendingAppTransitionStartCrossProfileApps();
break;
- case ANIM_REMOTE_ANIMATION:
- displayContent.mAppTransition.overridePendingAppTransitionRemote(
- pendingOptions.getRemoteAnimationAdapter());
- break;
case ANIM_NONE:
case ANIM_UNDEFINED:
break;
@@ -4033,35 +4051,32 @@
}
}
- void clearOptionsLocked() {
- clearOptionsLocked(true /* withAbort */);
- }
-
- void clearOptionsLocked(boolean withAbort) {
- if (withAbort && pendingOptions != null) {
- pendingOptions.abort();
+ void abortAndClearOptionsAnimation() {
+ if (mPendingOptions != null) {
+ mPendingOptions.abort();
}
- pendingOptions = null;
+ clearOptionsAnimation();
}
- ActivityOptions takeOptionsLocked(boolean fromClient) {
+ void clearOptionsAnimation() {
+ mPendingOptions = null;
+ mPendingRemoteAnimation = null;
+ }
+
+ ActivityOptions getOptions() {
+ return mPendingOptions;
+ }
+
+ ActivityOptions takeOptions() {
if (DEBUG_TRANSITION) Slog.i(TAG, "Taking options for " + this + " callers="
+ Debug.getCallers(6));
- ActivityOptions opts = pendingOptions;
-
- // If we are trying to take activity options from the client, do not null it out if it's a
- // remote animation as the client doesn't need it ever. This is a workaround when client is
- // faster to take the options than we are to resume the next activity.
- // TODO (b/132432864): Fix the root cause of these transition preparing/applying options
- // timing somehow
- if (!fromClient || opts == null || opts.getRemoteAnimationAdapter() == null) {
- pendingOptions = null;
- }
+ final ActivityOptions opts = mPendingOptions;
+ mPendingOptions = null;
return opts;
}
boolean allowMoveToFront() {
- return pendingOptions == null || !pendingOptions.getAvoidMoveToFront();
+ return mPendingOptions == null || !mPendingOptions.getAvoidMoveToFront();
}
void removeUriPermissionsLocked() {
@@ -4883,7 +4898,7 @@
try {
mAtmService.getLifecycleManager().scheduleTransaction(app.getThread(), appToken,
- StartActivityItem.obtain());
+ StartActivityItem.obtain(takeOptions()));
} catch (Exception e) {
Slog.w(TAG, "Exception thrown sending start: " + intent.getComponent(), e);
}
@@ -5204,7 +5219,7 @@
notifyAppStopped();
if (finishing) {
- clearOptionsLocked();
+ abortAndClearOptionsAnimation();
} else {
if (deferRelaunchUntilPaused) {
destroyImmediately("stop-config");
@@ -5838,8 +5853,8 @@
// We don't show starting window for overlay activities.
return;
}
- if (pendingOptions != null
- && pendingOptions.getAnimationType() == ActivityOptions.ANIM_SCENE_TRANSITION) {
+ if (mPendingOptions != null
+ && mPendingOptions.getAnimationType() == ActivityOptions.ANIM_SCENE_TRANSITION) {
// Don't show starting window when using shared element transition.
return;
}
@@ -6539,7 +6554,7 @@
* aspect ratio.
*/
boolean shouldUseSizeCompatMode() {
- if (info.supportsSizeChanges) {
+ if (info.supportsSizeChanges() != ActivityInfo.SIZE_CHANGES_UNSUPPORTED) {
return false;
}
if (inMultiWindowMode() || getWindowConfiguration().hasWindowDecorCaption()) {
diff --git a/services/core/java/com/android/server/wm/ActivityStartController.java b/services/core/java/com/android/server/wm/ActivityStartController.java
index f9e85cd..2dd8c59 100644
--- a/services/core/java/com/android/server/wm/ActivityStartController.java
+++ b/services/core/java/com/android/server/wm/ActivityStartController.java
@@ -528,7 +528,7 @@
"pendingActivityLaunch");
try {
starter.startResolvedActivity(pal.r, pal.sourceRecord, null, null, pal.startFlags,
- resume, pal.r.pendingOptions, null, pal.intentGrants);
+ resume, pal.r.getOptions(), null, pal.intentGrants);
} catch (Exception e) {
Slog.e(TAG, "Exception during pending activity launch pal=" + pal, e);
pal.sendErrorResult(e.getMessage());
diff --git a/services/core/java/com/android/server/wm/ActivityStarter.java b/services/core/java/com/android/server/wm/ActivityStarter.java
index e30cd05..5289f86 100644
--- a/services/core/java/com/android/server/wm/ActivityStarter.java
+++ b/services/core/java/com/android/server/wm/ActivityStarter.java
@@ -1258,7 +1258,7 @@
}
// We pretend to the caller that it was really started to make it backward compatible, but
// they will just get a cancel result.
- ActivityOptions.abort(r.pendingOptions);
+ ActivityOptions.abort(r.getOptions());
return true;
}
diff --git a/services/core/java/com/android/server/wm/ActivityTaskManagerService.java b/services/core/java/com/android/server/wm/ActivityTaskManagerService.java
index ea04c64..cd5ea46 100644
--- a/services/core/java/com/android/server/wm/ActivityTaskManagerService.java
+++ b/services/core/java/com/android/server/wm/ActivityTaskManagerService.java
@@ -34,7 +34,6 @@
import static android.app.ActivityTaskManager.RESIZE_MODE_PRESERVE_WINDOW;
import static android.app.WindowConfiguration.ACTIVITY_TYPE_DREAM;
import static android.app.WindowConfiguration.WINDOWING_MODE_PINNED;
-import static android.app.WindowConfiguration.WINDOWING_MODE_SPLIT_SCREEN_PRIMARY;
import static android.app.WindowConfiguration.WINDOWING_MODE_UNDEFINED;
import static android.content.Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS;
import static android.content.Intent.FLAG_ACTIVITY_NEW_TASK;
@@ -1902,9 +1901,6 @@
@Override
public boolean setTaskWindowingMode(int taskId, int windowingMode, boolean toTop) {
- if (windowingMode == WINDOWING_MODE_SPLIT_SCREEN_PRIMARY) {
- return setTaskWindowingModeSplitScreenPrimary(taskId, toTop);
- }
enforceCallerIsRecentsOrHasPermission(MANAGE_ACTIVITY_TASKS, "setTaskWindowingMode()");
synchronized (mGlobalLock) {
final long ident = Binder.clearCallingIdentity();
@@ -2235,28 +2231,6 @@
}
/**
- * Moves the specified task to the primary-split-screen stack.
- *
- * @param taskId Id of task to move.
- * @param toTop If the task and stack should be moved to the top.
- * @return Whether the task was successfully put into splitscreen.
- */
- @Override
- public boolean setTaskWindowingModeSplitScreenPrimary(int taskId, boolean toTop) {
- enforceCallerIsRecentsOrHasPermission(MANAGE_ACTIVITY_TASKS,
- "setTaskWindowingModeSplitScreenPrimary()");
- synchronized (mGlobalLock) {
- final long ident = Binder.clearCallingIdentity();
- try {
- return setTaskWindowingModeSplitScreen(taskId, WINDOWING_MODE_SPLIT_SCREEN_PRIMARY,
- toTop);
- } finally {
- Binder.restoreCallingIdentity(ident);
- }
- }
- }
-
- /**
* Moves the specified task into a split-screen tile.
*/
private boolean setTaskWindowingModeSplitScreen(int taskId, int windowingMode, boolean toTop) {
diff --git a/services/core/java/com/android/server/wm/ActivityTaskSupervisor.java b/services/core/java/com/android/server/wm/ActivityTaskSupervisor.java
index 16f415f..9d291b1 100644
--- a/services/core/java/com/android/server/wm/ActivityTaskSupervisor.java
+++ b/services/core/java/com/android/server/wm/ActivityTaskSupervisor.java
@@ -868,8 +868,8 @@
mergedConfiguration.getOverrideConfiguration(), r.compat,
r.launchedFromPackage, task.voiceInteractor, proc.getReportedProcState(),
r.getSavedState(), r.getPersistentSavedState(), results, newIntents,
- dc.isNextTransitionForward(), proc.createProfilerInfoIfNeeded(),
- r.assistToken, activityClientController,
+ r.takeOptions(), dc.isNextTransitionForward(),
+ proc.createProfilerInfoIfNeeded(), r.assistToken, activityClientController,
r.createFixedRotationAdjustmentsIfNeeded()));
// Set desired final state.
@@ -2566,9 +2566,10 @@
try {
mService.moveTaskToFrontLocked(null /* appThread */, null /* callingPackage */,
task.mTaskId, 0, options);
- // Apply options to prevent pendingOptions be taken by client to make sure
- // the override pending app transition will be applied immediately.
- targetActivity.applyOptionsLocked();
+ // Apply options to prevent pendingOptions be taken when scheduling activity
+ // lifecycle transaction to make sure the override pending app transition will
+ // be applied immediately.
+ targetActivity.applyOptionsAnimation();
} finally {
mActivityMetricsLogger.notifyActivityLaunched(launchingState,
START_TASK_TO_FRONT, targetActivity, activityOptions);
diff --git a/services/core/java/com/android/server/wm/BackgroundActivityStartCallback.java b/services/core/java/com/android/server/wm/BackgroundActivityStartCallback.java
index af6c255..200f207 100644
--- a/services/core/java/com/android/server/wm/BackgroundActivityStartCallback.java
+++ b/services/core/java/com/android/server/wm/BackgroundActivityStartCallback.java
@@ -18,25 +18,29 @@
import android.os.IBinder;
+import java.util.Collection;
+
/**
- * Callback to be called when a background activity start is allowed exclusively because of the
- * token provided in {@link #getToken()}.
+ * Callback to decide activity starts and related operations based on originating tokens.
*/
public interface BackgroundActivityStartCallback {
/**
- * The token for which this callback is responsible for deciding whether the app can start
- * background activities or not.
+ * Returns true if the background activity start originating from {@code tokens} should be
+ * allowed or not.
*
- * Ideally this should just return a final variable, don't do anything costly here (don't hold
- * any locks).
- */
- IBinder getToken();
-
- /**
- * Returns true if the background activity start due to originating token in {@link #getToken()}
- * should be allowed or not.
+ * Note that if the start was allowed due to a mechanism other than tokens (eg. permission),
+ * this won't be called.
*
* This will be called holding the WM lock, don't do anything costly here.
*/
- boolean isActivityStartAllowed(int uid, String packageName);
+ boolean isActivityStartAllowed(Collection<IBinder> tokens, int uid, String packageName);
+
+ /**
+ * Returns whether {@code uid} can send {@link android.content.Intent
+ * #ACTION_CLOSE_SYSTEM_DIALOGS}, presumably to start activities, based on the originating
+ * tokens {@code tokens} currently associated with potential activity starts.
+ *
+ * This will be called holding the AM and WM lock, don't do anything costly here.
+ */
+ boolean canCloseSystemDialogs(Collection<IBinder> tokens, int uid);
}
diff --git a/services/core/java/com/android/server/wm/DisplayFrames.java b/services/core/java/com/android/server/wm/DisplayFrames.java
index 7f3cb49..38d0c21 100644
--- a/services/core/java/com/android/server/wm/DisplayFrames.java
+++ b/services/core/java/com/android/server/wm/DisplayFrames.java
@@ -16,11 +16,17 @@
package com.android.server.wm;
+import static android.view.InsetsState.ITYPE_BOTTOM_DISPLAY_CUTOUT;
+import static android.view.InsetsState.ITYPE_LEFT_DISPLAY_CUTOUT;
+import static android.view.InsetsState.ITYPE_RIGHT_DISPLAY_CUTOUT;
+import static android.view.InsetsState.ITYPE_TOP_DISPLAY_CUTOUT;
+
import android.annotation.NonNull;
import android.graphics.Rect;
import android.util.proto.ProtoOutputStream;
import android.view.DisplayCutout;
import android.view.DisplayInfo;
+import android.view.InsetsState;
import com.android.server.wm.utils.WmDisplayCutout;
@@ -67,25 +73,41 @@
mDisplayInfoCutout = displayCutout != null ? displayCutout : WmDisplayCutout.NO_CUTOUT;
}
- public void onBeginLayout() {
- mUnrestricted.set(0, 0, mDisplayWidth, mDisplayHeight);
+ public void onBeginLayout(InsetsState state) {
mDisplayCutout = mDisplayInfoCutout;
- mDisplayCutoutSafe.set(Integer.MIN_VALUE, Integer.MIN_VALUE,
- Integer.MAX_VALUE, Integer.MAX_VALUE);
- if (!mDisplayCutout.getDisplayCutout().isEmpty()) {
- final DisplayCutout c = mDisplayCutout.getDisplayCutout();
- if (c.getSafeInsetLeft() > 0) {
- mDisplayCutoutSafe.left = mUnrestricted.left + c.getSafeInsetLeft();
+ final Rect unrestricted = mUnrestricted;
+ final Rect safe = mDisplayCutoutSafe;
+ final DisplayCutout cutout = mDisplayCutout.getDisplayCutout();
+ unrestricted.set(0, 0, mDisplayWidth, mDisplayHeight);
+ safe.set(Integer.MIN_VALUE, Integer.MIN_VALUE, Integer.MAX_VALUE, Integer.MAX_VALUE);
+ state.setDisplayFrame(unrestricted);
+ state.setDisplayCutout(cutout);
+ if (!cutout.isEmpty()) {
+ if (cutout.getSafeInsetLeft() > 0) {
+ safe.left = unrestricted.left + cutout.getSafeInsetLeft();
}
- if (c.getSafeInsetTop() > 0) {
- mDisplayCutoutSafe.top = mUnrestricted.top + c.getSafeInsetTop();
+ if (cutout.getSafeInsetTop() > 0) {
+ safe.top = unrestricted.top + cutout.getSafeInsetTop();
}
- if (c.getSafeInsetRight() > 0) {
- mDisplayCutoutSafe.right = mUnrestricted.right - c.getSafeInsetRight();
+ if (cutout.getSafeInsetRight() > 0) {
+ safe.right = unrestricted.right - cutout.getSafeInsetRight();
}
- if (c.getSafeInsetBottom() > 0) {
- mDisplayCutoutSafe.bottom = mUnrestricted.bottom - c.getSafeInsetBottom();
+ if (cutout.getSafeInsetBottom() > 0) {
+ safe.bottom = unrestricted.bottom - cutout.getSafeInsetBottom();
}
+ state.getSource(ITYPE_LEFT_DISPLAY_CUTOUT).setFrame(
+ unrestricted.left, unrestricted.top, safe.left, unrestricted.bottom);
+ state.getSource(ITYPE_TOP_DISPLAY_CUTOUT).setFrame(
+ unrestricted.left, unrestricted.top, unrestricted.right, safe.top);
+ state.getSource(ITYPE_RIGHT_DISPLAY_CUTOUT).setFrame(
+ safe.right, unrestricted.top, unrestricted.right, unrestricted.bottom);
+ state.getSource(ITYPE_BOTTOM_DISPLAY_CUTOUT).setFrame(
+ unrestricted.left, safe.bottom, unrestricted.right, unrestricted.bottom);
+ } else {
+ state.removeSource(ITYPE_LEFT_DISPLAY_CUTOUT);
+ state.removeSource(ITYPE_TOP_DISPLAY_CUTOUT);
+ state.removeSource(ITYPE_RIGHT_DISPLAY_CUTOUT);
+ state.removeSource(ITYPE_BOTTOM_DISPLAY_CUTOUT);
}
}
diff --git a/services/core/java/com/android/server/wm/DisplayPolicy.java b/services/core/java/com/android/server/wm/DisplayPolicy.java
index cd02e00..fb005b3 100644
--- a/services/core/java/com/android/server/wm/DisplayPolicy.java
+++ b/services/core/java/com/android/server/wm/DisplayPolicy.java
@@ -25,20 +25,16 @@
import static android.content.res.Configuration.UI_MODE_TYPE_CAR;
import static android.content.res.Configuration.UI_MODE_TYPE_MASK;
import static android.view.Display.TYPE_INTERNAL;
-import static android.view.InsetsState.ITYPE_BOTTOM_DISPLAY_CUTOUT;
import static android.view.InsetsState.ITYPE_BOTTOM_GESTURES;
import static android.view.InsetsState.ITYPE_BOTTOM_TAPPABLE_ELEMENT;
import static android.view.InsetsState.ITYPE_CAPTION_BAR;
import static android.view.InsetsState.ITYPE_CLIMATE_BAR;
import static android.view.InsetsState.ITYPE_EXTRA_NAVIGATION_BAR;
import static android.view.InsetsState.ITYPE_IME;
-import static android.view.InsetsState.ITYPE_LEFT_DISPLAY_CUTOUT;
import static android.view.InsetsState.ITYPE_LEFT_GESTURES;
import static android.view.InsetsState.ITYPE_NAVIGATION_BAR;
-import static android.view.InsetsState.ITYPE_RIGHT_DISPLAY_CUTOUT;
import static android.view.InsetsState.ITYPE_RIGHT_GESTURES;
import static android.view.InsetsState.ITYPE_STATUS_BAR;
-import static android.view.InsetsState.ITYPE_TOP_DISPLAY_CUTOUT;
import static android.view.InsetsState.ITYPE_TOP_GESTURES;
import static android.view.InsetsState.ITYPE_TOP_TAPPABLE_ELEMENT;
import static android.view.WindowInsetsController.APPEARANCE_LIGHT_NAVIGATION_BARS;
@@ -1408,15 +1404,13 @@
* @param attrs The LayoutParams of the window.
* @param windowToken The token of the window.
* @param outFrame The frame of the window.
- * @param outDisplayCutout The area that has been cut away from the display.
* @param outInsetsState The insets state of this display from the client's perspective.
* @param localClient Whether the client is from the our process.
* @return Whether to always consume the system bars.
* See {@link #areSystemBarsForcedShownLw(WindowState)}.
*/
boolean getLayoutHint(LayoutParams attrs, WindowToken windowToken, Rect outFrame,
- DisplayCutout.ParcelableWrapper outDisplayCutout, InsetsState outInsetsState,
- boolean localClient) {
+ InsetsState outInsetsState, boolean localClient) {
final boolean isFixedRotationTransforming =
windowToken != null && windowToken.isFixedRotationTransforming();
final ActivityRecord activity = windowToken != null ? windowToken.asActivityRecord() : null;
@@ -1432,19 +1426,6 @@
outFrame.intersect(taskBounds);
}
- final int fl = attrs.flags;
- final boolean layoutInScreenAndInsetDecor = (fl & FLAG_LAYOUT_IN_SCREEN) != 0
- && (fl & FLAG_LAYOUT_INSET_DECOR) != 0;
- final DisplayFrames displayFrames = isFixedRotationTransforming
- ? windowToken.getFixedRotationTransformDisplayFrames()
- : mDisplayContent.mDisplayFrames;
- if (layoutInScreenAndInsetDecor) {
- outDisplayCutout.set(
- displayFrames.mDisplayCutout.calculateRelativeTo(outFrame).getDisplayCutout());
- } else {
- outDisplayCutout.set(DisplayCutout.NO_CUTOUT);
- }
-
final boolean inSizeCompatMode = WindowState.inSizeCompatMode(attrs, windowToken);
outInsetsState.set(state, inSizeCompatMode || localClient);
if (inSizeCompatMode) {
@@ -1523,9 +1504,7 @@
*/
void simulateLayoutDisplay(DisplayFrames displayFrames, InsetsState insetsState,
SparseArray<Rect> barContentFrames) {
- displayFrames.onBeginLayout();
- updateInsetsStateForDisplayCutout(displayFrames, insetsState);
- insetsState.setDisplayFrame(displayFrames.mUnrestricted);
+ displayFrames.onBeginLayout(insetsState);
final WindowFrames simulatedWindowFrames = new WindowFrames();
if (mNavigationBar != null) {
simulateLayoutDecorWindow(mNavigationBar, displayFrames, insetsState,
@@ -1547,10 +1526,7 @@
* @param uiMode The current uiMode in configuration.
*/
public void beginLayoutLw(DisplayFrames displayFrames, int uiMode) {
- displayFrames.onBeginLayout();
- final InsetsState state = mDisplayContent.getInsetsStateController().getRawInsetsState();
- updateInsetsStateForDisplayCutout(displayFrames, state);
- state.setDisplayFrame(displayFrames.mUnrestricted);
+ displayFrames.onBeginLayout(mDisplayContent.getInsetsStateController().getRawInsetsState());
mSystemGestures.screenWidth = displayFrames.mUnrestricted.width();
mSystemGestures.screenHeight = displayFrames.mUnrestricted.height();
@@ -1595,23 +1571,6 @@
}
}
- private static void updateInsetsStateForDisplayCutout(DisplayFrames displayFrames,
- InsetsState state) {
- if (displayFrames.mDisplayCutout.getDisplayCutout().isEmpty()) {
- state.removeSource(ITYPE_LEFT_DISPLAY_CUTOUT);
- state.removeSource(ITYPE_TOP_DISPLAY_CUTOUT);
- state.removeSource(ITYPE_RIGHT_DISPLAY_CUTOUT);
- state.removeSource(ITYPE_BOTTOM_DISPLAY_CUTOUT);
- return;
- }
- final Rect u = displayFrames.mUnrestricted;
- final Rect s = displayFrames.mDisplayCutoutSafe;
- state.getSource(ITYPE_LEFT_DISPLAY_CUTOUT).setFrame(u.left, u.top, s.left, u.bottom);
- state.getSource(ITYPE_TOP_DISPLAY_CUTOUT).setFrame(u.left, u.top, u.right, s.top);
- state.getSource(ITYPE_RIGHT_DISPLAY_CUTOUT).setFrame(s.right, u.top, u.right, u.bottom);
- state.getSource(ITYPE_BOTTOM_DISPLAY_CUTOUT).setFrame(u.left, s.bottom, u.right, u.bottom);
- }
-
private void layoutStatusBar(DisplayFrames displayFrames, Rect simulatedContentFrame) {
// decide where the status bar goes ahead of time
if (mStatusBar == null) {
@@ -1623,7 +1582,7 @@
windowFrames.setFrames(sTmpStatusFrame /* parentFrame */,
sTmpStatusFrame /* displayFrame */);
// Let the status bar determine its size.
- mStatusBar.computeFrame(displayFrames);
+ mStatusBar.computeFrameAndUpdateSourceFrame();
// For layout, the status bar is always at the top with our fixed height.
int statusBarBottom = displayFrames.mUnrestricted.top
@@ -1690,7 +1649,7 @@
final WindowFrames windowFrames = mNavigationBar.getLayoutingWindowFrames();
windowFrames.setFrames(navigationFrame /* parentFrame */,
navigationFrame /* displayFrame */);
- mNavigationBar.computeFrame(displayFrames);
+ mNavigationBar.computeFrameAndUpdateSourceFrame();
final Rect contentFrame = sTmpRect;
contentFrame.set(windowFrames.mFrame);
contentFrame.intersect(displayFrames.mDisplayCutoutSafe);
@@ -1872,7 +1831,7 @@
windowFrames.setContentChanged(true);
}
- win.computeFrame(displayFrames);
+ win.computeFrameAndUpdateSourceFrame();
}
WindowState getTopFullscreenOpaqueWindow() {
diff --git a/services/core/java/com/android/server/wm/ResetTargetTaskHelper.java b/services/core/java/com/android/server/wm/ResetTargetTaskHelper.java
index 17cb890..fc347bc 100644
--- a/services/core/java/com/android/server/wm/ResetTargetTaskHelper.java
+++ b/services/core/java/com/android/server/wm/ResetTargetTaskHelper.java
@@ -267,8 +267,9 @@
private boolean takeOption(ActivityRecord p, boolean noOptions) {
mCanMoveOptions = false;
if (noOptions && mTopOptions == null) {
- mTopOptions = p.takeOptionsLocked(false /* fromClient */);
+ mTopOptions = p.getOptions();
if (mTopOptions != null) {
+ p.clearOptionsAnimation();
noOptions = false;
}
}
diff --git a/services/core/java/com/android/server/wm/Session.java b/services/core/java/com/android/server/wm/Session.java
index 57d48c6..0cefa95 100644
--- a/services/core/java/com/android/server/wm/Session.java
+++ b/services/core/java/com/android/server/wm/Session.java
@@ -61,7 +61,6 @@
import android.util.ArraySet;
import android.util.MergedConfiguration;
import android.util.Slog;
-import android.view.DisplayCutout;
import android.view.IWindow;
import android.view.IWindowId;
import android.view.IWindowSession;
@@ -185,22 +184,21 @@
@Override
public int addToDisplay(IWindow window, WindowManager.LayoutParams attrs,
int viewVisibility, int displayId, InsetsState requestedVisibility, Rect outFrame,
- DisplayCutout.ParcelableWrapper outDisplayCutout, InputChannel outInputChannel,
- InsetsState outInsetsState, InsetsSourceControl[] outActiveControls) {
+ InputChannel outInputChannel, InsetsState outInsetsState,
+ InsetsSourceControl[] outActiveControls) {
return mService.addWindow(this, window, attrs, viewVisibility, displayId,
- UserHandle.getUserId(mUid), requestedVisibility, outFrame, outDisplayCutout,
- outInputChannel, outInsetsState, outActiveControls);
+ UserHandle.getUserId(mUid), requestedVisibility, outFrame, outInputChannel,
+ outInsetsState, outActiveControls);
}
@Override
public int addToDisplayAsUser(IWindow window, WindowManager.LayoutParams attrs,
int viewVisibility, int displayId, int userId, InsetsState requestedVisibility,
- Rect outFrame, DisplayCutout.ParcelableWrapper outDisplayCutout,
- InputChannel outInputChannel, InsetsState outInsetsState,
+ Rect outFrame, InputChannel outInputChannel, InsetsState outInsetsState,
InsetsSourceControl[] outActiveControls) {
return mService.addWindow(this, window, attrs, viewVisibility, displayId, userId,
- requestedVisibility, outFrame, outDisplayCutout, outInputChannel, outInsetsState,
+ requestedVisibility, outFrame, outInputChannel, outInsetsState,
outActiveControls);
}
@@ -209,8 +207,8 @@
int viewVisibility, int displayId, InsetsState outInsetsState) {
return mService.addWindow(this, window, attrs, viewVisibility, displayId,
UserHandle.getUserId(mUid), mDummyRequestedVisibility,
- new Rect() /* outFrame */, new DisplayCutout.ParcelableWrapper() /* cutout */,
- null /* outInputChannel */, outInsetsState, mDummyControls);
+ new Rect() /* outFrame */, null /* outInputChannel */, outInsetsState,
+ mDummyControls);
}
@Override
diff --git a/services/core/java/com/android/server/wm/Task.java b/services/core/java/com/android/server/wm/Task.java
index 2290c23..81cbd61 100644
--- a/services/core/java/com/android/server/wm/Task.java
+++ b/services/core/java/com/android/server/wm/Task.java
@@ -1926,8 +1926,9 @@
if (r == boundaryActivity) return true;
if (!r.finishing) {
- final ActivityOptions opts = r.takeOptionsLocked(false /* fromClient */);
+ final ActivityOptions opts = r.getOptions();
if (opts != null) {
+ r.clearOptionsAnimation();
// TODO: Why is this updating the boundary activity vs. the current activity???
boundaryActivity.updateOptionsLocked(opts);
}
@@ -6247,9 +6248,9 @@
}
if (anim) {
- next.applyOptionsLocked();
+ next.applyOptionsAnimation();
} else {
- next.clearOptionsLocked();
+ next.abortAndClearOptionsAnimation();
}
mTaskSupervisor.mNoAnimActivities.clear();
@@ -6356,7 +6357,7 @@
mAtmService.getAppWarningsLocked().onResumeActivity(next);
next.app.setPendingUiCleanAndForceProcessStateUpTo(mAtmService.mTopProcessState);
- next.clearOptionsLocked();
+ next.abortAndClearOptionsAnimation();
transaction.setLifecycleStateRequest(
ResumeActivityItem.obtain(next.app.getReportedProcState(),
dc.isNextTransitionForward()));
diff --git a/services/core/java/com/android/server/wm/TaskSnapshotSurface.java b/services/core/java/com/android/server/wm/TaskSnapshotSurface.java
index 8c458a2..09df71c 100644
--- a/services/core/java/com/android/server/wm/TaskSnapshotSurface.java
+++ b/services/core/java/com/android/server/wm/TaskSnapshotSurface.java
@@ -227,7 +227,7 @@
int displayId = activity.getDisplayContent().getDisplayId();
try {
final int res = session.addToDisplay(window, layoutParams,
- View.GONE, displayId, mTmpInsetsState, tmpFrames.frame, tmpFrames.displayCutout,
+ View.GONE, displayId, mTmpInsetsState, tmpFrames.frame,
null /* outInputChannel */, mTmpInsetsState, mTempControls);
if (res < 0) {
Slog.w(TAG, "Failed to add snapshot starting window res=" + res);
diff --git a/services/core/java/com/android/server/wm/WindowFrames.java b/services/core/java/com/android/server/wm/WindowFrames.java
index 7991ec6..361694b 100644
--- a/services/core/java/com/android/server/wm/WindowFrames.java
+++ b/services/core/java/com/android/server/wm/WindowFrames.java
@@ -17,7 +17,6 @@
package com.android.server.wm;
import static com.android.server.wm.WindowFramesProto.CONTAINING_FRAME;
-import static com.android.server.wm.WindowFramesProto.CUTOUT;
import static com.android.server.wm.WindowFramesProto.DISPLAY_FRAME;
import static com.android.server.wm.WindowFramesProto.FRAME;
import static com.android.server.wm.WindowFramesProto.PARENT_FRAME;
@@ -25,9 +24,6 @@
import android.annotation.NonNull;
import android.graphics.Rect;
import android.util.proto.ProtoOutputStream;
-import android.view.DisplayCutout;
-
-import com.android.server.wm.utils.WmDisplayCutout;
import java.io.PrintWriter;
@@ -96,30 +92,11 @@
*/
private boolean mParentFrameWasClippedByDisplayCutout;
- /**
- * Part of the display that has been cut away. See {@link DisplayCutout}.
- */
- WmDisplayCutout mDisplayCutout = WmDisplayCutout.NO_CUTOUT;
-
- /**
- * The last cutout that has been reported to the client.
- */
- private WmDisplayCutout mLastDisplayCutout = WmDisplayCutout.NO_CUTOUT;
-
- private boolean mDisplayCutoutChanged;
-
boolean mLastForceReportingResized = false;
boolean mForceReportingResized = false;
private boolean mContentChanged;
- public WindowFrames() {
- }
-
- public WindowFrames(Rect parentFrame, Rect displayFrame) {
- setFrames(parentFrame, displayFrame);
- }
-
public void setFrames(Rect parentFrame, Rect displayFrame) {
mParentFrame.set(parentFrame);
mDisplayFrame.set(displayFrame);
@@ -134,10 +111,6 @@
return mParentFrameWasClippedByDisplayCutout;
}
- public void setDisplayCutout(WmDisplayCutout displayCutout) {
- mDisplayCutout = displayCutout;
- }
-
/**
* @return true if the width or height has changed since last reported to the client.
*/
@@ -157,8 +130,7 @@
boolean setReportResizeHints() {
mLastForceReportingResized |= mForceReportingResized;
mFrameSizeChanged |= didFrameSizeChange();
- mDisplayCutoutChanged |= !mLastDisplayCutout.equals(mDisplayCutout);
- return mLastForceReportingResized || mFrameSizeChanged || mDisplayCutoutChanged;
+ return mLastForceReportingResized || mFrameSizeChanged;
}
/**
@@ -168,7 +140,6 @@
void clearReportResizeHints() {
mLastForceReportingResized = false;
mFrameSizeChanged = false;
- mDisplayCutoutChanged = false;
}
/**
@@ -176,7 +147,6 @@
*/
void onResizeHandled() {
mForceReportingResized = false;
- mLastDisplayCutout = mDisplayCutout;
}
/**
@@ -207,7 +177,6 @@
mDisplayFrame.dumpDebug(proto, DISPLAY_FRAME);
mContainingFrame.dumpDebug(proto, CONTAINING_FRAME);
mFrame.dumpDebug(proto, FRAME);
- mDisplayCutout.getDisplayCutout().dumpDebug(proto, CUTOUT);
proto.end(token);
}
@@ -219,12 +188,9 @@
+ " display=" + mDisplayFrame.toShortString(sTmpSB));
pw.println(prefix + "mFrame=" + mFrame.toShortString(sTmpSB)
+ " last=" + mLastFrame.toShortString(sTmpSB));
- pw.println(prefix + " cutout=" + mDisplayCutout.getDisplayCutout()
- + " last=" + mLastDisplayCutout.getDisplayCutout());
}
String getInsetsChangedInfo() {
- return "forceReportingResized=" + mLastForceReportingResized
- + " displayCutoutChanged=" + mDisplayCutoutChanged;
+ return "forceReportingResized=" + mLastForceReportingResized;
}
}
diff --git a/services/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java
index 7794f23..292d7ea 100644
--- a/services/core/java/com/android/server/wm/WindowManagerService.java
+++ b/services/core/java/com/android/server/wm/WindowManagerService.java
@@ -27,7 +27,6 @@
import static android.Manifest.permission.WRITE_SECURE_SETTINGS;
import static android.app.ActivityManagerInternal.ALLOW_FULL_ONLY;
import static android.app.ActivityManagerInternal.ALLOW_NON_FULL;
-import static android.app.ActivityTaskManager.SPLIT_SCREEN_CREATE_MODE_TOP_OR_LEFT;
import static android.app.AppOpsManager.OP_SYSTEM_ALERT_WINDOW;
import static android.app.StatusBarManager.DISABLE_MASK;
import static android.app.WindowConfiguration.ROTATION_UNDEFINED;
@@ -220,7 +219,6 @@
import android.util.proto.ProtoOutputStream;
import android.view.Choreographer;
import android.view.Display;
-import android.view.DisplayCutout;
import android.view.DisplayInfo;
import android.view.Gravity;
import android.view.IAppTransitionAnimationSpecsFuture;
@@ -690,9 +688,6 @@
final BLASTSyncEngine mSyncEngine;
- int mDockedStackCreateMode = SPLIT_SCREEN_CREATE_MODE_TOP_OR_LEFT;
- Rect mDockedStackCreateBounds;
-
boolean mIsPc;
/**
* Flag that indicates that desktop mode is forced for public secondary screens.
@@ -1445,8 +1440,8 @@
public int addWindow(Session session, IWindow client, LayoutParams attrs, int viewVisibility,
int displayId, int requestUserId, InsetsState requestedVisibility, Rect outFrame,
- DisplayCutout.ParcelableWrapper outDisplayCutout, InputChannel outInputChannel,
- InsetsState outInsetsState, InsetsSourceControl[] outActiveControls) {
+ InputChannel outInputChannel, InsetsState outInsetsState,
+ InsetsSourceControl[] outActiveControls) {
Arrays.fill(outActiveControls, null);
int[] appOp = new int[1];
final boolean isRoundedCornerOverlay = (attrs.privateFlags
@@ -1759,8 +1754,8 @@
prepareNoneTransitionForRelaunching(activity);
}
- if (displayPolicy.getLayoutHint(win.mAttrs, token, outFrame, outDisplayCutout,
- outInsetsState, win.isClientLocal())) {
+ if (displayPolicy.getLayoutHint(win.mAttrs, token, outFrame, outInsetsState,
+ win.isClientLocal())) {
res |= WindowManagerGlobal.ADD_FLAG_ALWAYS_CONSUME_SYSTEM_BARS;
}
@@ -8392,7 +8387,7 @@
@Override
public boolean getWindowInsets(WindowManager.LayoutParams attrs, int displayId,
- DisplayCutout.ParcelableWrapper outDisplayCutout, InsetsState outInsetsState) {
+ InsetsState outInsetsState) {
final boolean fromLocal = Binder.getCallingPid() == myPid();
final long origId = Binder.clearCallingIdentity();
try {
@@ -8404,7 +8399,7 @@
}
final WindowToken windowToken = dc.getWindowToken(attrs.token);
return dc.getDisplayPolicy().getLayoutHint(attrs, windowToken,
- mTmpRect /* outFrame */, outDisplayCutout, outInsetsState, fromLocal);
+ mTmpRect /* outFrame */, outInsetsState, fromLocal);
}
} finally {
Binder.restoreCallingIdentity(origId);
diff --git a/services/core/java/com/android/server/wm/WindowProcessController.java b/services/core/java/com/android/server/wm/WindowProcessController.java
index 9d64af7..90949cb 100644
--- a/services/core/java/com/android/server/wm/WindowProcessController.java
+++ b/services/core/java/com/android/server/wm/WindowProcessController.java
@@ -585,9 +585,8 @@
}
/**
- * If there are no tokens, we don't allow *by token*. If there are tokens, we need to check if
- * the callback handles all the tokens, if so we ask the callback if the activity should be
- * started, otherwise we allow.
+ * If there are no tokens, we don't allow *by token*. If there are tokens, we ask the callback
+ * if the start is allowed for these tokens, otherwise if there is no callback we allow.
*/
private boolean isBackgroundStartAllowedByToken() {
if (mBackgroundActivityStartTokens.isEmpty()) {
@@ -597,16 +596,22 @@
// We have tokens but no callback to decide => allow
return true;
}
- IBinder callbackToken = mBackgroundActivityStartCallback.getToken();
- for (IBinder token : mBackgroundActivityStartTokens.values()) {
- if (token != callbackToken) {
- // The callback doesn't handle all the tokens => allow
- return true;
- }
+ // The callback will decide
+ return mBackgroundActivityStartCallback.isActivityStartAllowed(
+ mBackgroundActivityStartTokens.values(), mInfo.uid, mInfo.packageName);
+ }
+
+ /**
+ * Returns whether this process is allowed to close system dialogs via a background activity
+ * start token that allows the close system dialogs operation (eg. notification).
+ */
+ public boolean canCloseSystemDialogsByToken() {
+ synchronized (mAtm.mGlobalLock) {
+ return !mBackgroundActivityStartTokens.isEmpty()
+ && mBackgroundActivityStartCallback != null
+ && mBackgroundActivityStartCallback.canCloseSystemDialogs(
+ mBackgroundActivityStartTokens.values(), mInfo.uid);
}
- // The callback handles all the tokens => callback decides
- return mBackgroundActivityStartCallback.isActivityStartAllowed(mInfo.uid,
- mInfo.packageName);
}
private boolean isBoundByForegroundUid() {
diff --git a/services/core/java/com/android/server/wm/WindowState.java b/services/core/java/com/android/server/wm/WindowState.java
index a8f4bae..d1ea9a2 100644
--- a/services/core/java/com/android/server/wm/WindowState.java
+++ b/services/core/java/com/android/server/wm/WindowState.java
@@ -252,7 +252,6 @@
import com.android.server.policy.WindowManagerPolicy;
import com.android.server.wm.LocalAnimationAdapter.AnimationSpec;
import com.android.server.wm.SurfaceAnimator.AnimationType;
-import com.android.server.wm.utils.WmDisplayCutout;
import java.io.PrintWriter;
import java.lang.ref.WeakReference;
@@ -1071,8 +1070,7 @@
frame.inset(left, top, right, bottom);
}
- void computeFrame(DisplayFrames displayFrames) {
- getLayoutingWindowFrames().setDisplayCutout(displayFrames.mDisplayCutout);
+ void computeFrameAndUpdateSourceFrame() {
computeFrame();
// Update the source frame to provide insets to other windows during layout. If the
// simulated frames exist, then this is not computing a stable result so just skip.
@@ -1213,9 +1211,6 @@
}
}
- windowFrames.setDisplayCutout(
- windowFrames.mDisplayCutout.calculateRelativeTo(windowFrames.mFrame));
-
// Offset the actual frame by the amount layout frame is off.
windowFrames.offsetFrames(-layoutXDiff, -layoutYDiff);
@@ -1292,10 +1287,6 @@
return mWindowFrames.mContainingFrame;
}
- WmDisplayCutout getWmDisplayCutout() {
- return mWindowFrames.mDisplayCutout;
- }
-
void getCompatFrameSize(Rect outFrame) {
outFrame.set(0, 0, mWindowFrames.mCompatFrame.width(), mWindowFrames.mCompatFrame.height());
}
@@ -3577,7 +3568,6 @@
final DisplayInfo displayInfo = getDisplayInfo();
backdropFrame.set(0, 0, displayInfo.logicalWidth, displayInfo.logicalHeight);
}
- outFrames.displayCutout.set(mWindowFrames.mDisplayCutout.getDisplayCutout());
}
void reportResized() {
diff --git a/services/core/java/com/android/server/wm/utils/WmDisplayCutout.java b/services/core/java/com/android/server/wm/utils/WmDisplayCutout.java
index 46fff03..ee3f4f4d 100644
--- a/services/core/java/com/android/server/wm/utils/WmDisplayCutout.java
+++ b/services/core/java/com/android/server/wm/utils/WmDisplayCutout.java
@@ -57,55 +57,6 @@
}
/**
- * Insets the reference frame of the cutout in the given directions.
- *
- * @return a copy of this instance which has been inset
- * @hide
- */
- public WmDisplayCutout inset(int insetLeft, int insetTop, int insetRight, int insetBottom) {
- DisplayCutout newInner = mInner.inset(insetLeft, insetTop, insetRight, insetBottom);
-
- if (mInner == newInner) {
- return this;
- }
-
- Size frame = mFrameSize == null ? null : new Size(
- mFrameSize.getWidth() - insetLeft - insetRight,
- mFrameSize.getHeight() - insetTop - insetBottom);
-
- return new WmDisplayCutout(newInner, frame);
- }
-
- /**
- * Recalculates the cutout relative to the given reference frame.
- *
- * The safe insets must already have been computed, e.g. with {@link #computeSafeInsets}.
- *
- * @return a copy of this instance with the safe insets recalculated
- * @hide
- */
- public WmDisplayCutout calculateRelativeTo(Rect frame) {
- if (mFrameSize == null) {
- return this;
- }
- final int insetRight = mFrameSize.getWidth() - frame.right;
- final int insetBottom = mFrameSize.getHeight() - frame.bottom;
- if (frame.left == 0 && frame.top == 0 && insetRight == 0 && insetBottom == 0) {
- return this;
- }
- if (frame.left >= mInner.getSafeInsetLeft()
- && frame.top >= mInner.getSafeInsetTop()
- && insetRight >= mInner.getSafeInsetRight()
- && insetBottom >= mInner.getSafeInsetBottom()) {
- return NO_CUTOUT;
- }
- if (mInner.isEmpty()) {
- return this;
- }
- return inset(frame.left, frame.top, insetRight, insetBottom);
- }
-
- /**
* Calculates the safe insets relative to the given display size.
*
* @return a copy of this instance with the safe insets calculated
diff --git a/services/core/jni/com_android_server_input_InputManagerService.cpp b/services/core/jni/com_android_server_input_InputManagerService.cpp
index 1d55318..d0c2050 100644
--- a/services/core/jni/com_android_server_input_InputManagerService.cpp
+++ b/services/core/jni/com_android_server_input_InputManagerService.cpp
@@ -2055,7 +2055,6 @@
->enableSensor(deviceId, static_cast<InputDeviceSensorType>(sensorType),
std::chrono::microseconds(samplingPeriodUs),
std::chrono::microseconds(maxBatchReportLatencyUs));
- return true;
}
static void nativeDisableSensor(JNIEnv* env, jclass /* clazz */, jlong ptr, jint deviceId,
diff --git a/services/core/jni/com_android_server_location_GnssLocationProvider.cpp b/services/core/jni/com_android_server_location_GnssLocationProvider.cpp
index 066dbce..e3a8bb4 100644
--- a/services/core/jni/com_android_server_location_GnssLocationProvider.cpp
+++ b/services/core/jni/com_android_server_location_GnssLocationProvider.cpp
@@ -1442,7 +1442,7 @@
};
/* Initializes the GNSS service handle. */
-static void android_location_GnssLocationProvider_set_gps_service_handle() {
+static void android_location_gnss_hal_GnssNative_set_gps_service_handle() {
gnssHalAidl = waitForVintfService<IGnssAidl>();
if (gnssHalAidl != nullptr) {
ALOGD("Successfully got GNSS AIDL handle.");
@@ -1489,9 +1489,9 @@
}
/* One time initialization at system boot */
-static void android_location_GnssNative_class_init_once(JNIEnv* env, jclass clazz) {
+static void android_location_gnss_hal_GnssNative_class_init_once(JNIEnv* env, jclass clazz) {
// Initialize the top level gnss HAL handle.
- android_location_GnssLocationProvider_set_gps_service_handle();
+ android_location_gnss_hal_GnssNative_set_gps_service_handle();
// Cache methodIDs and class IDs.
method_reportLocation = env->GetMethodID(clazz, "reportLocation",
@@ -1655,8 +1655,8 @@
}
/* Initialization needed at system boot and whenever GNSS service dies. */
-static void android_location_GnssNative_init_once(JNIEnv* env, jobject obj,
- jboolean reinitializeGnssServiceHandle) {
+static void android_location_gnss_hal_GnssNative_init_once(JNIEnv* env, jobject obj,
+ jboolean reinitializeGnssServiceHandle) {
/*
* Save a pointer to JVM.
*/
@@ -1666,7 +1666,7 @@
}
if (reinitializeGnssServiceHandle) {
- android_location_GnssLocationProvider_set_gps_service_handle();
+ android_location_gnss_hal_GnssNative_set_gps_service_handle();
}
if (gnssHal == nullptr) {
@@ -1934,7 +1934,7 @@
}
}
-static jboolean android_location_GnssNative_is_supported(JNIEnv* /* env */, jclass /* clazz */) {
+static jboolean android_location_gnss_hal_GnssNative_is_supported(JNIEnv* /* env */, jclass) {
return (gnssHal != nullptr) ? JNI_TRUE : JNI_FALSE;
}
@@ -1952,7 +1952,7 @@
}
/* Initialization needed each time the GPS service is shutdown. */
-static jboolean android_location_GnssLocationProvider_init(JNIEnv* /* env */, jobject /* obj */) {
+static jboolean android_location_gnss_hal_GnssNative_init(JNIEnv* /* env */, jclass) {
/*
* This must be set before calling into the HAL library.
*/
@@ -2087,7 +2087,7 @@
return JNI_TRUE;
}
-static void android_location_GnssLocationProvider_cleanup(JNIEnv* /* env */, jobject /* obj */) {
+static void android_location_gnss_hal_GnssNative_cleanup(JNIEnv* /* env */, jclass) {
if (gnssHal == nullptr) {
return;
}
@@ -2096,9 +2096,9 @@
checkHidlReturn(result, "IGnss cleanup() failed.");
}
-static jboolean android_location_GnssLocationProvider_set_position_mode(JNIEnv* /* env */,
- jobject /* obj */, jint mode, jint recurrence, jint min_interval, jint preferred_accuracy,
- jint preferred_time, jboolean low_power_mode) {
+static jboolean android_location_gnss_hal_GnssNative_set_position_mode(
+ JNIEnv* /* env */, jclass, jint mode, jint recurrence, jint min_interval,
+ jint preferred_accuracy, jint preferred_time, jboolean low_power_mode) {
Return<bool> result = false;
if (gnssHal_V1_1 != nullptr) {
result = gnssHal_V1_1->setPositionMode_1_1(static_cast<IGnss_V1_0::GnssPositionMode>(mode),
@@ -2118,7 +2118,7 @@
return checkHidlReturn(result, "IGnss setPositionMode() failed.");
}
-static jboolean android_location_GnssLocationProvider_start(JNIEnv* /* env */, jobject /* obj */) {
+static jboolean android_location_gnss_hal_GnssNative_start(JNIEnv* /* env */, jclass) {
if (gnssHal == nullptr) {
return JNI_FALSE;
}
@@ -2127,7 +2127,7 @@
return checkHidlReturn(result, "IGnss start() failed.");
}
-static jboolean android_location_GnssLocationProvider_stop(JNIEnv* /* env */, jobject /* obj */) {
+static jboolean android_location_gnss_hal_GnssNative_stop(JNIEnv* /* env */, jclass) {
if (gnssHal == nullptr) {
return JNI_FALSE;
}
@@ -2136,8 +2136,7 @@
return checkHidlReturn(result, "IGnss stop() failed.");
}
-static void android_location_GnssLocationProvider_delete_aiding_data(JNIEnv* /* env */,
- jobject /* obj */,
+static void android_location_gnss_hal_GnssNative_delete_aiding_data(JNIEnv* /* env */, jclass,
jint flags) {
if (gnssHal == nullptr) {
return;
@@ -2147,8 +2146,8 @@
checkHidlReturn(result, "IGnss deleteAidingData() failed.");
}
-static void android_location_GnssLocationProvider_agps_set_reference_location_cellid(
- JNIEnv* /* env */, jobject /* obj */, jint type, jint mcc, jint mnc, jint lac, jint cid) {
+static void android_location_gnss_hal_GnssNative_agps_set_reference_location_cellid(
+ JNIEnv* /* env */, jclass, jint type, jint mcc, jint mnc, jint lac, jint cid) {
IAGnssRil_V1_0::AGnssRefLocation location;
if (agnssRilIface == nullptr) {
@@ -2175,8 +2174,8 @@
checkHidlReturn(result, "IAGnssRil setRefLocation() failed.");
}
-static void android_location_GnssLocationProvider_agps_set_id(JNIEnv* env, jobject /* obj */,
- jint type, jstring setid_string) {
+static void android_location_gnss_hal_GnssNative_agps_set_id(JNIEnv* env, jclass, jint type,
+ jstring setid_string) {
if (agnssRilIface == nullptr) {
ALOGE("%s: IAGnssRil interface not available.", __func__);
return;
@@ -2187,8 +2186,8 @@
checkHidlReturn(result, "IAGnssRil setSetId() failed.");
}
-static jint android_location_GnssLocationProvider_read_nmea(JNIEnv* env, jobject /* obj */,
- jbyteArray nmeaArray, jint buffer_size) {
+static jint android_location_gnss_hal_GnssNative_read_nmea(JNIEnv* env, jclass,
+ jbyteArray nmeaArray, jint buffer_size) {
// this should only be called from within a call to reportNmea
jbyte* nmea = reinterpret_cast<jbyte *>(env->GetPrimitiveArrayCritical(nmeaArray, 0));
int length = GnssCallback::sNmeaStringLength;
@@ -2199,8 +2198,9 @@
return (jint) length;
}
-static void android_location_GnssLocationProvider_inject_time(JNIEnv* /* env */, jobject /* obj */,
- jlong time, jlong timeReference, jint uncertainty) {
+static void android_location_gnss_hal_GnssNative_inject_time(JNIEnv* /* env */, jclass, jlong time,
+ jlong timeReference,
+ jint uncertainty) {
if (gnssHal == nullptr) {
return;
}
@@ -2209,22 +2209,12 @@
checkHidlReturn(result, "IGnss injectTime() failed.");
}
-static void android_location_GnssLocationProvider_inject_best_location(
- JNIEnv*,
- jobject,
- jint gnssLocationFlags,
- jdouble latitudeDegrees,
- jdouble longitudeDegrees,
- jdouble altitudeMeters,
- jfloat speedMetersPerSec,
- jfloat bearingDegrees,
- jfloat horizontalAccuracyMeters,
- jfloat verticalAccuracyMeters,
- jfloat speedAccuracyMetersPerSecond,
- jfloat bearingAccuracyDegrees,
- jlong timestamp,
- jint elapsedRealtimeFlags,
- jlong elapsedRealtimeNanos,
+static void android_location_gnss_hal_GnssNative_inject_best_location(
+ JNIEnv* /* env */, jclass, jint gnssLocationFlags, jdouble latitudeDegrees,
+ jdouble longitudeDegrees, jdouble altitudeMeters, jfloat speedMetersPerSec,
+ jfloat bearingDegrees, jfloat horizontalAccuracyMeters, jfloat verticalAccuracyMeters,
+ jfloat speedAccuracyMetersPerSecond, jfloat bearingAccuracyDegrees, jlong timestamp,
+ jint elapsedRealtimeFlags, jlong elapsedRealtimeNanos,
jdouble elapsedRealtimeUncertaintyNanos) {
if (gnssHal_V2_0 != nullptr) {
GnssLocation_V2_0 location = createGnssLocation_V2_0(
@@ -2267,8 +2257,10 @@
ALOGE("IGnss injectBestLocation() is called but gnssHal_V1_1 is not available.");
}
-static void android_location_GnssLocationProvider_inject_location(JNIEnv* /* env */,
- jobject /* obj */, jdouble latitude, jdouble longitude, jfloat accuracy) {
+static void android_location_gnss_hal_GnssNative_inject_location(JNIEnv* /* env */, jclass,
+ jdouble latitude,
+ jdouble longitude,
+ jfloat accuracy) {
if (gnssHal == nullptr) {
return;
}
@@ -2277,16 +2269,15 @@
checkHidlReturn(result, "IGnss injectLocation() failed.");
}
-static jboolean android_location_GnssLocationProvider_supports_psds(
- JNIEnv* /* env */, jobject /* obj */) {
+static jboolean android_location_gnss_hal_GnssNative_supports_psds(JNIEnv* /* env */, jclass) {
return (gnssPsdsAidlIface != nullptr || gnssPsdsIface != nullptr || gnssXtraIface != nullptr)
? JNI_TRUE
: JNI_FALSE;
}
-static void android_location_GnssLocationProvider_inject_psds_data(JNIEnv* env, jobject /* obj */,
- jbyteArray data, jint length,
- jint psdsType) {
+static void android_location_gnss_hal_GnssNative_inject_psds_data(JNIEnv* env, jclass,
+ jbyteArray data, jint length,
+ jint psdsType) {
if (gnssPsdsAidlIface == nullptr && gnssPsdsIface == nullptr && gnssXtraIface == nullptr) {
ALOGE("%s: IGnssPsds or IGnssXtra interface not available.", __func__);
return;
@@ -2406,8 +2397,8 @@
}
}
-static void android_location_GnssLocationProvider_set_agps_server(JNIEnv* env, jobject /* obj */,
- jint type, jstring hostname, jint port) {
+static void android_location_gnss_hal_GnssNative_set_agps_server(JNIEnv* env, jclass, jint type,
+ jstring hostname, jint port) {
if (agnssIface_V2_0 != nullptr) {
AGnssDispatcher::setServer<IAGnss_V2_0, IAGnssCallback_V2_0>(agnssIface_V2_0, env, type,
hostname, port);
@@ -2420,8 +2411,8 @@
}
}
-static void android_location_GnssLocationProvider_send_ni_response(JNIEnv* /* env */,
- jobject /* obj */, jint notifId, jint response) {
+static void android_location_gnss_hal_GnssNative_send_ni_response(JNIEnv* /* env */, jclass,
+ jint notifId, jint response) {
if (gnssNiIface == nullptr) {
ALOGE("%s: IGnssNi interface not available.", __func__);
return;
@@ -2504,8 +2495,7 @@
return (jstring) env->NewStringUTF(internalState.str().c_str());
}
-static jstring android_location_GnssLocationProvider_get_internal_state(JNIEnv* env,
- jobject /* obj */) {
+static jstring android_location_gnss_hal_GnssNative_get_internal_state(JNIEnv* env, jclass) {
jstring internalStateStr = nullptr;
/*
* TODO: Create a jobject to represent GnssDebug.
@@ -2537,8 +2527,7 @@
return internalStateStr;
}
-static void android_location_GnssLocationProvider_request_power_stats(JNIEnv* env,
- jobject /* obj */) {
+static void android_location_gnss_hal_GnssNative_request_power_stats(JNIEnv* env) {
if (gnssPowerIndicationIface == nullptr) {
return;
}
@@ -2546,8 +2535,8 @@
checkAidlStatus(status, "IGnssPowerIndication requestGnssPowerStats() failed.");
}
-static jboolean android_location_GnssLocationProvider_is_gnss_visibility_control_supported(
- JNIEnv* /* env */, jclass /* clazz */) {
+static jboolean android_location_gnss_hal_GnssNative_is_gnss_visibility_control_supported(
+ JNIEnv* /* env */, jclass) {
return (gnssVisibilityControlIface != nullptr) ? JNI_TRUE : JNI_FALSE;
}
@@ -2587,15 +2576,15 @@
}
}
-static jboolean android_location_GnssGeofenceProvider_is_geofence_supported(
- JNIEnv* /* env */, jobject /* obj */) {
+static jboolean android_location_gnss_hal_GnssNative_is_geofence_supported(JNIEnv* /* env */,
+ jclass) {
return (gnssGeofencingIface != nullptr) ? JNI_TRUE : JNI_FALSE;
}
-static jboolean android_location_GnssGeofenceProvider_add_geofence(JNIEnv* /* env */,
- jobject /* obj */, jint geofenceId, jdouble latitude, jdouble longitude, jdouble radius,
- jint last_transition, jint monitor_transition, jint notification_responsiveness,
- jint unknown_timer) {
+static jboolean android_location_gnss_hal_GnssNative_add_geofence(
+ JNIEnv* /* env */, jclass, jint geofenceId, jdouble latitude, jdouble longitude,
+ jdouble radius, jint last_transition, jint monitor_transition,
+ jint notification_responsiveness, jint unknown_timer) {
if (gnssGeofencingIface == nullptr) {
ALOGE("%s: IGnssGeofencing interface not available.", __func__);
return JNI_FALSE;
@@ -2608,8 +2597,8 @@
return checkHidlReturn(result, "IGnssGeofencing addGeofence() failed.");
}
-static jboolean android_location_GnssGeofenceProvider_remove_geofence(JNIEnv* /* env */,
- jobject /* obj */, jint geofenceId) {
+static jboolean android_location_gnss_hal_GnssNative_remove_geofence(JNIEnv* /* env */, jclass,
+ jint geofenceId) {
if (gnssGeofencingIface == nullptr) {
ALOGE("%s: IGnssGeofencing interface not available.", __func__);
return JNI_FALSE;
@@ -2619,8 +2608,8 @@
return checkHidlReturn(result, "IGnssGeofencing removeGeofence() failed.");
}
-static jboolean android_location_GnssGeofenceProvider_pause_geofence(JNIEnv* /* env */,
- jobject /* obj */, jint geofenceId) {
+static jboolean android_location_gnss_hal_GnssNative_pause_geofence(JNIEnv* /* env */, jclass,
+ jint geofenceId) {
if (gnssGeofencingIface == nullptr) {
ALOGE("%s: IGnssGeofencing interface not available.", __func__);
return JNI_FALSE;
@@ -2630,8 +2619,9 @@
return checkHidlReturn(result, "IGnssGeofencing pauseGeofence() failed.");
}
-static jboolean android_location_GnssGeofenceProvider_resume_geofence(JNIEnv* /* env */,
- jobject /* obj */, jint geofenceId, jint monitor_transition) {
+static jboolean android_location_gnss_hal_GnssNative_resume_geofence(JNIEnv* /* env */, jclass,
+ jint geofenceId,
+ jint monitor_transition) {
if (gnssGeofencingIface == nullptr) {
ALOGE("%s: IGnssGeofencing interface not available.", __func__);
return JNI_FALSE;
@@ -2641,16 +2631,16 @@
return checkHidlReturn(result, "IGnssGeofencing resumeGeofence() failed.");
}
-static jboolean android_location_GnssAntennaInfoProvider_is_antenna_info_supported(JNIEnv* env,
- jclass clazz) {
+static jboolean android_location_gnss_hal_GnssNative_is_antenna_info_supported(JNIEnv* env,
+ jclass) {
if (gnssAntennaInfoIface != nullptr) {
return JNI_TRUE;
}
return JNI_FALSE;
}
-static jboolean android_location_GnssAntennaInfoProvider_start_antenna_info_listening(
- JNIEnv* /* env */, jobject /* obj */) {
+static jboolean android_location_gnss_hal_GnssNative_start_antenna_info_listening(JNIEnv* /* env */,
+ jclass) {
if (gnssAntennaInfoIface == nullptr) {
ALOGE("%s: IGnssAntennaInfo interface not available.", __func__);
return JNI_FALSE;
@@ -2676,8 +2666,8 @@
return JNI_TRUE;
}
-static jboolean android_location_GnssAntennaInfoProvider_stop_antenna_info_listening(
- JNIEnv* /* env */, jobject /* obj */) {
+static jboolean android_location_gnss_hal_GnssNative_stop_antenna_info_listening(JNIEnv* /* env */,
+ jclass) {
if (gnssAntennaInfoIface == nullptr) {
ALOGE("%s: IGnssAntennaInfo interface not available.", __func__);
return JNI_FALSE;
@@ -2687,8 +2677,7 @@
return checkHidlReturn(result, "IGnssAntennaInfo close() failed.");
}
-static jboolean android_location_GnssMeasurementsProvider_is_measurement_supported(
- JNIEnv* env, jclass clazz) {
+static jboolean android_location_gnss_hal_GnssNative_is_measurement_supported(JNIEnv* env, jclass) {
if (gnssMeasurementIface != nullptr) {
return JNI_TRUE;
}
@@ -2696,10 +2685,8 @@
return JNI_FALSE;
}
-static jboolean android_location_GnssMeasurementsProvider_start_measurement_collection(
- JNIEnv* /* env */,
- jobject /* obj */,
- jboolean enableFullTracking) {
+static jboolean android_location_gnss_hal_GnssNative_start_measurement_collection(
+ JNIEnv* /* env */, jclass, jboolean enableFullTracking) {
if (gnssMeasurementIface == nullptr) {
ALOGE("%s: IGnssMeasurement interface not available.", __func__);
return JNI_FALSE;
@@ -2710,9 +2697,8 @@
enableFullTracking);
}
-static jboolean android_location_GnssMeasurementsProvider_stop_measurement_collection(
- JNIEnv* env,
- jobject obj) {
+static jboolean android_location_gnss_hal_GnssNative_stop_measurement_collection(JNIEnv* env,
+ jclass) {
if (gnssMeasurementIface == nullptr) {
ALOGE("%s: IGnssMeasurement interface not available.", __func__);
return JNI_FALSE;
@@ -2721,9 +2707,8 @@
return gnssMeasurementIface->close();
}
-static jboolean
- android_location_GnssMeasurementCorrectionsProvider_is_measurement_corrections_supported(
- JNIEnv* env, jclass clazz) {
+static jboolean android_location_gnss_hal_GnssNative_is_measurement_corrections_supported(
+ JNIEnv* env, jclass) {
if (gnssCorrectionsIface_V1_0 != nullptr || gnssCorrectionsIface_V1_1 != nullptr) {
return JNI_TRUE;
}
@@ -2816,12 +2801,9 @@
list[i] = singleSatCorrection;
}
}
-static jboolean
- android_location_GnssMeasurementCorrectionsProvider_inject_gnss_measurement_corrections(
- JNIEnv* env,
- jobject obj /* clazz*/,
- jobject correctionsObj) {
+static jboolean android_location_gnss_hal_GnssNative_inject_measurement_corrections(
+ JNIEnv* env, jclass, jobject correctionsObj) {
if (gnssCorrectionsIface_V1_0 == nullptr && gnssCorrectionsIface_V1_1 == nullptr) {
ALOGW("Trying to inject GNSS measurement corrections on a chipset that does not"
" support them.");
@@ -2893,18 +2875,16 @@
return checkHidlReturn(result, "IMeasurementCorrections 1.0 setCorrections() failed.");
}
-static jboolean android_location_GnssNavigationMessageProvider_is_navigation_message_supported(
- JNIEnv* env,
- jclass clazz) {
+static jboolean android_location_gnss_hal_GnssNative_is_navigation_message_supported(JNIEnv* env,
+ jclass) {
if (gnssNavigationMessageIface != nullptr) {
return JNI_TRUE;
}
return JNI_FALSE;
}
-static jboolean android_location_GnssNavigationMessageProvider_start_navigation_message_collection(
- JNIEnv* env,
- jobject obj) {
+static jboolean android_location_gnss_hal_GnssNative_start_navigation_message_collection(
+ JNIEnv* env, jclass) {
if (gnssNavigationMessageIface == nullptr) {
ALOGE("%s: IGnssNavigationMessage interface not available.", __func__);
return JNI_FALSE;
@@ -2926,9 +2906,8 @@
return JNI_TRUE;
}
-static jboolean android_location_GnssNavigationMessageProvider_stop_navigation_message_collection(
- JNIEnv* env,
- jobject obj) {
+static jboolean android_location_gnss_hal_GnssNative_stop_navigation_message_collection(JNIEnv* env,
+ jclass) {
if (gnssNavigationMessageIface == nullptr) {
ALOGE("%s: IGnssNavigationMessage interface not available.", __func__);
return JNI_FALSE;
@@ -3027,7 +3006,7 @@
return gnssConfigurationIface->setEsExtensionSec(emergencyExtensionSeconds);
}
-static jint android_location_GnssLocationProvider_get_batch_size(JNIEnv*, jclass) {
+static jint android_location_gnss_hal_GnssNative_get_batch_size(JNIEnv*) {
if (gnssBatchingIface == nullptr) {
return 0; // batching not supported, size = 0
}
@@ -3039,7 +3018,7 @@
return static_cast<jint>(result);
}
-static jboolean android_location_GnssLocationProvider_init_batching(JNIEnv*, jclass) {
+static jboolean android_location_gnss_hal_GnssNative_init_batching(JNIEnv*, jclass) {
if (gnssBatchingIface_V2_0 != nullptr) {
sp<IGnssBatchingCallback_V2_0> gnssBatchingCbIface_V2_0 = new GnssBatchingCallback_V2_0();
auto result = gnssBatchingIface_V2_0->init_2_0(gnssBatchingCbIface_V2_0);
@@ -3053,7 +3032,7 @@
}
}
-static void android_location_GnssLocationProvider_cleanup_batching(JNIEnv*, jclass) {
+static void android_location_gnss_hal_GnssNative_cleanup_batching(JNIEnv*, jclass) {
if (gnssBatchingIface == nullptr) {
return; // batching not supported
}
@@ -3061,9 +3040,8 @@
checkHidlReturn(result, "IGnssBatching cleanup() failed.");
}
-static jboolean android_location_GnssLocationProvider_start_batch(JNIEnv*, jclass,
- jlong periodNanos,
- jboolean wakeOnFifoFull) {
+static jboolean android_location_gnss_hal_GnssNative_start_batch(JNIEnv*, jclass, jlong periodNanos,
+ jboolean wakeOnFifoFull) {
if (gnssBatchingIface == nullptr) {
return JNI_FALSE; // batching not supported
}
@@ -3080,7 +3058,7 @@
return checkHidlReturn(result, "IGnssBatching start() failed.");
}
-static void android_location_GnssLocationProvider_flush_batch(JNIEnv*, jclass) {
+static void android_location_gnss_hal_GnssNative_flush_batch(JNIEnv*, jclass) {
if (gnssBatchingIface == nullptr) {
return; // batching not supported
}
@@ -3088,7 +3066,7 @@
checkHidlReturn(result, "IGnssBatching flush() failed.");
}
-static jboolean android_location_GnssLocationProvider_stop_batch(JNIEnv*, jclass) {
+static jboolean android_location_gnss_hal_GnssNative_stop_batch(JNIEnv*, jclass) {
if (gnssBatchingIface == nullptr) {
return JNI_FALSE; // batching not supported
}
@@ -3118,156 +3096,146 @@
static const JNINativeMethod sCoreMethods[] = {
/* name, signature, funcPtr */
{"native_class_init_once", "()V",
- reinterpret_cast<void*>(android_location_GnssNative_class_init_once)},
+ reinterpret_cast<void*>(android_location_gnss_hal_GnssNative_class_init_once)},
{"native_is_supported", "()Z",
- reinterpret_cast<void*>(android_location_GnssNative_is_supported)},
+ reinterpret_cast<void*>(android_location_gnss_hal_GnssNative_is_supported)},
{"native_init_once", "(Z)V",
- reinterpret_cast<void*>(android_location_GnssNative_init_once)},
+ reinterpret_cast<void*>(android_location_gnss_hal_GnssNative_init_once)},
};
static const JNINativeMethod sLocationProviderMethods[] = {
/* name, signature, funcPtr */
- {"native_init", "()Z", reinterpret_cast<void*>(android_location_GnssLocationProvider_init)},
+ {"native_init", "()Z", reinterpret_cast<void*>(android_location_gnss_hal_GnssNative_init)},
{"native_cleanup", "()V",
- reinterpret_cast<void*>(android_location_GnssLocationProvider_cleanup)},
+ reinterpret_cast<void*>(android_location_gnss_hal_GnssNative_cleanup)},
{"native_set_position_mode", "(IIIIIZ)Z",
- reinterpret_cast<void*>(android_location_GnssLocationProvider_set_position_mode)},
+ reinterpret_cast<void*>(android_location_gnss_hal_GnssNative_set_position_mode)},
{"native_start", "()Z",
- reinterpret_cast<void*>(android_location_GnssLocationProvider_start)},
- {"native_stop", "()Z", reinterpret_cast<void*>(android_location_GnssLocationProvider_stop)},
+ reinterpret_cast<void*>(android_location_gnss_hal_GnssNative_start)},
+ {"native_stop", "()Z", reinterpret_cast<void*>(android_location_gnss_hal_GnssNative_stop)},
{"native_delete_aiding_data", "(I)V",
- reinterpret_cast<void*>(android_location_GnssLocationProvider_delete_aiding_data)},
+ reinterpret_cast<void*>(android_location_gnss_hal_GnssNative_delete_aiding_data)},
{"native_read_nmea", "([BI)I",
- reinterpret_cast<void*>(android_location_GnssLocationProvider_read_nmea)},
+ reinterpret_cast<void*>(android_location_gnss_hal_GnssNative_read_nmea)},
{"native_inject_time", "(JJI)V",
- reinterpret_cast<void*>(android_location_GnssLocationProvider_inject_time)},
+ reinterpret_cast<void*>(android_location_gnss_hal_GnssNative_inject_time)},
{"native_inject_best_location", "(IDDDFFFFFFJIJD)V",
- reinterpret_cast<void*>(android_location_GnssLocationProvider_inject_best_location)},
+ reinterpret_cast<void*>(android_location_gnss_hal_GnssNative_inject_best_location)},
{"native_inject_location", "(DDF)V",
- reinterpret_cast<void*>(android_location_GnssLocationProvider_inject_location)},
+ reinterpret_cast<void*>(android_location_gnss_hal_GnssNative_inject_location)},
{"native_supports_psds", "()Z",
- reinterpret_cast<void*>(android_location_GnssLocationProvider_supports_psds)},
+ reinterpret_cast<void*>(android_location_gnss_hal_GnssNative_supports_psds)},
{"native_inject_psds_data", "([BII)V",
- reinterpret_cast<void*>(android_location_GnssLocationProvider_inject_psds_data)},
+ reinterpret_cast<void*>(android_location_gnss_hal_GnssNative_inject_psds_data)},
{"native_agps_set_id", "(ILjava/lang/String;)V",
- reinterpret_cast<void*>(android_location_GnssLocationProvider_agps_set_id)},
+ reinterpret_cast<void*>(android_location_gnss_hal_GnssNative_agps_set_id)},
{"native_agps_set_ref_location_cellid", "(IIIII)V",
reinterpret_cast<void*>(
- android_location_GnssLocationProvider_agps_set_reference_location_cellid)},
+ android_location_gnss_hal_GnssNative_agps_set_reference_location_cellid)},
{"native_set_agps_server", "(ILjava/lang/String;I)V",
- reinterpret_cast<void*>(android_location_GnssLocationProvider_set_agps_server)},
+ reinterpret_cast<void*>(android_location_gnss_hal_GnssNative_set_agps_server)},
{"native_send_ni_response", "(II)V",
- reinterpret_cast<void*>(android_location_GnssLocationProvider_send_ni_response)},
+ reinterpret_cast<void*>(android_location_gnss_hal_GnssNative_send_ni_response)},
{"native_get_internal_state", "()Ljava/lang/String;",
- reinterpret_cast<void*>(android_location_GnssLocationProvider_get_internal_state)},
+ reinterpret_cast<void*>(android_location_gnss_hal_GnssNative_get_internal_state)},
{"native_is_gnss_visibility_control_supported", "()Z",
reinterpret_cast<void*>(
- android_location_GnssLocationProvider_is_gnss_visibility_control_supported)},
+ android_location_gnss_hal_GnssNative_is_gnss_visibility_control_supported)},
};
-static const JNINativeMethod sMethodsBatching[] = {
+static const JNINativeMethod sBatchingMethods[] = {
/* name, signature, funcPtr */
{"native_get_batch_size", "()I",
- reinterpret_cast<void*>(android_location_GnssLocationProvider_get_batch_size)},
+ reinterpret_cast<void*>(android_location_gnss_hal_GnssNative_get_batch_size)},
{"native_start_batch", "(JZ)Z",
- reinterpret_cast<void*>(android_location_GnssLocationProvider_start_batch)},
+ reinterpret_cast<void*>(android_location_gnss_hal_GnssNative_start_batch)},
{"native_flush_batch", "()V",
- reinterpret_cast<void*>(android_location_GnssLocationProvider_flush_batch)},
+ reinterpret_cast<void*>(android_location_gnss_hal_GnssNative_flush_batch)},
{"native_stop_batch", "()Z",
- reinterpret_cast<void*>(android_location_GnssLocationProvider_stop_batch)},
+ reinterpret_cast<void*>(android_location_gnss_hal_GnssNative_stop_batch)},
{"native_init_batching", "()Z",
- reinterpret_cast<void*>(android_location_GnssLocationProvider_init_batching)},
+ reinterpret_cast<void*>(android_location_gnss_hal_GnssNative_init_batching)},
{"native_cleanup_batching", "()V",
- reinterpret_cast<void*>(android_location_GnssLocationProvider_cleanup_batching)},
+ reinterpret_cast<void*>(android_location_gnss_hal_GnssNative_cleanup_batching)},
};
static const JNINativeMethod sAntennaInfoMethods[] = {
/* name, signature, funcPtr */
{"native_is_antenna_info_supported", "()Z",
- reinterpret_cast<void*>(
- android_location_GnssAntennaInfoProvider_is_antenna_info_supported)},
+ reinterpret_cast<void*>(android_location_gnss_hal_GnssNative_is_antenna_info_supported)},
{"native_start_antenna_info_listening", "()Z",
reinterpret_cast<void*>(
- android_location_GnssAntennaInfoProvider_start_antenna_info_listening)},
+ android_location_gnss_hal_GnssNative_start_antenna_info_listening)},
{"native_stop_antenna_info_listening", "()Z",
- reinterpret_cast<void*>(
- android_location_GnssAntennaInfoProvider_stop_antenna_info_listening)},
+ reinterpret_cast<void*>(android_location_gnss_hal_GnssNative_stop_antenna_info_listening)},
};
static const JNINativeMethod sGeofenceMethods[] = {
- /* name, signature, funcPtr */
- {"native_is_geofence_supported",
- "()Z",
- reinterpret_cast<void *>(android_location_GnssGeofenceProvider_is_geofence_supported)},
- {"native_add_geofence",
- "(IDDDIIII)Z",
- reinterpret_cast<void *>(android_location_GnssGeofenceProvider_add_geofence)},
- {"native_remove_geofence",
- "(I)Z",
- reinterpret_cast<void *>(android_location_GnssGeofenceProvider_remove_geofence)},
- {"native_pause_geofence", "(I)Z", reinterpret_cast<void *>(
- android_location_GnssGeofenceProvider_pause_geofence)},
- {"native_resume_geofence",
- "(II)Z",
- reinterpret_cast<void *>(android_location_GnssGeofenceProvider_resume_geofence)},
+ /* name, signature, funcPtr */
+ {"native_is_geofence_supported", "()Z",
+ reinterpret_cast<void*>(android_location_gnss_hal_GnssNative_is_geofence_supported)},
+ {"native_add_geofence", "(IDDDIIII)Z",
+ reinterpret_cast<void*>(android_location_gnss_hal_GnssNative_add_geofence)},
+ {"native_remove_geofence", "(I)Z",
+ reinterpret_cast<void*>(android_location_gnss_hal_GnssNative_remove_geofence)},
+ {"native_pause_geofence", "(I)Z",
+ reinterpret_cast<void*>(android_location_gnss_hal_GnssNative_pause_geofence)},
+ {"native_resume_geofence", "(II)Z",
+ reinterpret_cast<void*>(android_location_gnss_hal_GnssNative_resume_geofence)},
};
static const JNINativeMethod sMeasurementMethods[] = {
- /* name, signature, funcPtr */
- {"native_is_measurement_supported", "()Z",
- reinterpret_cast<void*>(
- android_location_GnssMeasurementsProvider_is_measurement_supported)},
- {"native_start_measurement_collection", "(Z)Z",
- reinterpret_cast<void*>(
- android_location_GnssMeasurementsProvider_start_measurement_collection)},
- {"native_stop_measurement_collection", "()Z",
- reinterpret_cast<void*>(
- android_location_GnssMeasurementsProvider_stop_measurement_collection)},
+ /* name, signature, funcPtr */
+ {"native_is_measurement_supported", "()Z",
+ reinterpret_cast<void*>(android_location_gnss_hal_GnssNative_is_measurement_supported)},
+ {"native_start_measurement_collection", "(Z)Z",
+ reinterpret_cast<void*>(
+ android_location_gnss_hal_GnssNative_start_measurement_collection)},
+ {"native_stop_measurement_collection", "()Z",
+ reinterpret_cast<void*>(android_location_gnss_hal_GnssNative_stop_measurement_collection)},
};
static const JNINativeMethod sMeasurementCorrectionsMethods[] = {
- /* name, signature, funcPtr */
- {"native_is_measurement_corrections_supported", "()Z",
- reinterpret_cast<void*>(
- android_location_GnssMeasurementCorrectionsProvider_is_measurement_corrections_supported)},
- {"native_inject_gnss_measurement_corrections",
- "(Landroid/location/GnssMeasurementCorrections;)Z",
- reinterpret_cast<void*>(
- android_location_GnssMeasurementCorrectionsProvider_inject_gnss_measurement_corrections)},
+ /* name, signature, funcPtr */
+ {"native_is_measurement_corrections_supported", "()Z",
+ reinterpret_cast<void*>(
+ android_location_gnss_hal_GnssNative_is_measurement_corrections_supported)},
+ {"native_inject_measurement_corrections",
+ "(Landroid/location/GnssMeasurementCorrections;)Z",
+ reinterpret_cast<void*>(
+ android_location_gnss_hal_GnssNative_inject_measurement_corrections)},
};
static const JNINativeMethod sNavigationMessageMethods[] = {
- /* name, signature, funcPtr */
- {"native_is_navigation_message_supported",
- "()Z",
- reinterpret_cast<void *>(
- android_location_GnssNavigationMessageProvider_is_navigation_message_supported)},
- {"native_start_navigation_message_collection",
- "()Z",
- reinterpret_cast<void *>(
- android_location_GnssNavigationMessageProvider_start_navigation_message_collection)},
- {"native_stop_navigation_message_collection",
- "()Z",
- reinterpret_cast<void *>(
- android_location_GnssNavigationMessageProvider_stop_navigation_message_collection)},
+ /* name, signature, funcPtr */
+ {"native_is_navigation_message_supported", "()Z",
+ reinterpret_cast<void*>(
+ android_location_gnss_hal_GnssNative_is_navigation_message_supported)},
+ {"native_start_navigation_message_collection", "()Z",
+ reinterpret_cast<void*>(
+ android_location_gnss_hal_GnssNative_start_navigation_message_collection)},
+ {"native_stop_navigation_message_collection", "()Z",
+ reinterpret_cast<void*>(
+ android_location_gnss_hal_GnssNative_stop_navigation_message_collection)},
};
static const JNINativeMethod sNetworkConnectivityMethods[] = {
- /* name, signature, funcPtr */
- {"native_is_agps_ril_supported", "()Z",
- reinterpret_cast<void *>(android_location_GnssNetworkConnectivityHandler_is_agps_ril_supported)},
- {"native_update_network_state",
- "(ZIZZLjava/lang/String;JS)V",
- reinterpret_cast<void *>(android_location_GnssNetworkConnectivityHandler_update_network_state)},
- {"native_agps_data_conn_open",
- "(JLjava/lang/String;I)V",
- reinterpret_cast<void *>(android_location_GnssNetworkConnectivityHandler_agps_data_conn_open)},
- {"native_agps_data_conn_closed",
- "()V",
- reinterpret_cast<void *>(android_location_GnssNetworkConnectivityHandler_agps_data_conn_closed)},
- {"native_agps_data_conn_failed",
- "()V",
- reinterpret_cast<void *>(android_location_GnssNetworkConnectivityHandler_agps_data_conn_failed)},
+ /* name, signature, funcPtr */
+ {"native_is_agps_ril_supported", "()Z",
+ reinterpret_cast<void*>(
+ android_location_GnssNetworkConnectivityHandler_is_agps_ril_supported)},
+ {"native_update_network_state", "(ZIZZLjava/lang/String;JS)V",
+ reinterpret_cast<void*>(
+ android_location_GnssNetworkConnectivityHandler_update_network_state)},
+ {"native_agps_data_conn_open", "(JLjava/lang/String;I)V",
+ reinterpret_cast<void*>(
+ android_location_GnssNetworkConnectivityHandler_agps_data_conn_open)},
+ {"native_agps_data_conn_closed", "()V",
+ reinterpret_cast<void*>(
+ android_location_GnssNetworkConnectivityHandler_agps_data_conn_closed)},
+ {"native_agps_data_conn_failed", "()V",
+ reinterpret_cast<void*>(
+ android_location_GnssNetworkConnectivityHandler_agps_data_conn_failed)},
};
static const JNINativeMethod sConfigurationMethods[] = {
@@ -3297,45 +3265,73 @@
};
static const JNINativeMethod sVisibilityControlMethods[] = {
- /* name, signature, funcPtr */
- {"native_enable_nfw_location_access",
- "([Ljava/lang/String;)Z",
- reinterpret_cast<void *>(
- android_location_GnssVisibilityControl_enable_nfw_location_access)},
+ /* name, signature, funcPtr */
+ {"native_enable_nfw_location_access", "([Ljava/lang/String;)Z",
+ reinterpret_cast<void*>(
+ android_location_GnssVisibilityControl_enable_nfw_location_access)},
};
static const JNINativeMethod sPowerIndicationMethods[] = {
/* name, signature, funcPtr */
{"native_request_power_stats", "()V",
- reinterpret_cast<void*>(android_location_GnssLocationProvider_request_power_stats)},
+ reinterpret_cast<void*>(android_location_gnss_hal_GnssNative_request_power_stats)},
};
int register_android_server_location_GnssLocationProvider(JNIEnv* env) {
- jniRegisterNativeMethods(env, "com/android/server/location/gnss/GnssAntennaInfoProvider",
- sAntennaInfoMethods, NELEM(sAntennaInfoMethods));
- jniRegisterNativeMethods(env, "com/android/server/location/gnss/GnssLocationProvider",
- sMethodsBatching, NELEM(sMethodsBatching));
- jniRegisterNativeMethods(env, "com/android/server/location/gnss/GnssGeofenceProvider",
- sGeofenceMethods, NELEM(sGeofenceMethods));
- jniRegisterNativeMethods(env, "com/android/server/location/gnss/GnssMeasurementsProvider",
- sMeasurementMethods, NELEM(sMeasurementMethods));
- jniRegisterNativeMethods(env,
- "com/android/server/location/gnss/GnssMeasurementCorrectionsProvider",
- sMeasurementCorrectionsMethods, NELEM(sMeasurementCorrectionsMethods));
- jniRegisterNativeMethods(env, "com/android/server/location/gnss/GnssNavigationMessageProvider",
- sNavigationMessageMethods, NELEM(sNavigationMessageMethods));
- jniRegisterNativeMethods(env, "com/android/server/location/gnss/GnssNetworkConnectivityHandler",
- sNetworkConnectivityMethods, NELEM(sNetworkConnectivityMethods));
- jniRegisterNativeMethods(env, "com/android/server/location/gnss/GnssConfiguration",
- sConfigurationMethods, NELEM(sConfigurationMethods));
- jniRegisterNativeMethods(env, "com/android/server/location/gnss/GnssVisibilityControl",
- sVisibilityControlMethods, NELEM(sVisibilityControlMethods));
- jniRegisterNativeMethods(env, "com/android/server/location/gnss/GnssPowerIndicationProvider",
- sPowerIndicationMethods, NELEM(sPowerIndicationMethods));
- jniRegisterNativeMethods(env, "com/android/server/location/gnss/GnssLocationProvider",
- sLocationProviderMethods, NELEM(sLocationProviderMethods));
- return jniRegisterNativeMethods(env, "com/android/server/location/gnss/GnssNative",
- sCoreMethods, NELEM(sCoreMethods));
+ int res;
+
+ res = jniRegisterNativeMethods(env, "com/android/server/location/gnss/hal/GnssNative",
+ sAntennaInfoMethods, NELEM(sAntennaInfoMethods));
+ LOG_FATAL_IF(res < 0, "Unable to register native methods.");
+
+ res = jniRegisterNativeMethods(env, "com/android/server/location/gnss/hal/GnssNative",
+ sBatchingMethods, NELEM(sBatchingMethods));
+ LOG_FATAL_IF(res < 0, "Unable to register native methods.");
+
+ res = jniRegisterNativeMethods(env, "com/android/server/location/gnss/hal/GnssNative",
+ sGeofenceMethods, NELEM(sGeofenceMethods));
+ LOG_FATAL_IF(res < 0, "Unable to register native methods.");
+
+ res = jniRegisterNativeMethods(env, "com/android/server/location/gnss/hal/GnssNative",
+ sMeasurementMethods, NELEM(sMeasurementMethods));
+ LOG_FATAL_IF(res < 0, "Unable to register native methods.");
+
+ res = jniRegisterNativeMethods(env, "com/android/server/location/gnss/hal/GnssNative",
+ sMeasurementCorrectionsMethods,
+ NELEM(sMeasurementCorrectionsMethods));
+ LOG_FATAL_IF(res < 0, "Unable to register native methods.");
+
+ res = jniRegisterNativeMethods(env, "com/android/server/location/gnss/hal/GnssNative",
+ sNavigationMessageMethods, NELEM(sNavigationMessageMethods));
+ LOG_FATAL_IF(res < 0, "Unable to register native methods.");
+
+ res = jniRegisterNativeMethods(env,
+ "com/android/server/location/gnss/"
+ "GnssNetworkConnectivityHandler",
+ sNetworkConnectivityMethods, NELEM(sNetworkConnectivityMethods));
+ LOG_FATAL_IF(res < 0, "Unable to register native methods.");
+
+ res = jniRegisterNativeMethods(env, "com/android/server/location/gnss/GnssConfiguration",
+ sConfigurationMethods, NELEM(sConfigurationMethods));
+ LOG_FATAL_IF(res < 0, "Unable to register native methods.");
+
+ res = jniRegisterNativeMethods(env, "com/android/server/location/gnss/GnssVisibilityControl",
+ sVisibilityControlMethods, NELEM(sVisibilityControlMethods));
+ LOG_FATAL_IF(res < 0, "Unable to register native methods.");
+
+ res = jniRegisterNativeMethods(env, "com/android/server/location/gnss/hal/GnssNative",
+ sPowerIndicationMethods, NELEM(sPowerIndicationMethods));
+ LOG_FATAL_IF(res < 0, "Unable to register native methods.");
+
+ res = jniRegisterNativeMethods(env, "com/android/server/location/gnss/hal/GnssNative",
+ sLocationProviderMethods, NELEM(sLocationProviderMethods));
+ LOG_FATAL_IF(res < 0, "Unable to register native methods.");
+
+ res = jniRegisterNativeMethods(env, "com/android/server/location/gnss/hal/GnssNative",
+ sCoreMethods, NELEM(sCoreMethods));
+ LOG_FATAL_IF(res < 0, "Unable to register native methods.");
+
+ return 0;
}
} /* namespace android */
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
index 5f6d76be..7b4c1be 100644
--- a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
@@ -7620,10 +7620,9 @@
+ " as profile owner on user " + currentForegroundUser);
// Sets profile owner on current foreground user since
// the human user will complete the DO setup workflow from there.
- mInjector.binderWithCleanCallingIdentity(() ->
- manageUserUnchecked(/* deviceOwner= */ admin, /* profileOwner= */ admin,
- /* managedUser= */ currentForegroundUser,
- /* adminExtras= */ null));
+ manageUserUnchecked(/* deviceOwner= */ admin, /* profileOwner= */ admin,
+ /* managedUser= */ currentForegroundUser,
+ /* adminExtras= */ null);
}
return true;
}
diff --git a/services/robotests/src/com/android/server/location/gnss/GnssGeofenceProviderTest.java b/services/robotests/src/com/android/server/location/gnss/GnssGeofenceProviderTest.java
deleted file mode 100644
index 48e6ce8..0000000
--- a/services/robotests/src/com/android/server/location/gnss/GnssGeofenceProviderTest.java
+++ /dev/null
@@ -1,155 +0,0 @@
-/*
- * Copyright (C) 2020 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.server.location.gnss;
-
-import static org.mockito.ArgumentMatchers.anyDouble;
-import static org.mockito.ArgumentMatchers.anyInt;
-import static org.mockito.ArgumentMatchers.eq;
-import static org.mockito.Mockito.times;
-import static org.mockito.Mockito.verify;
-import static org.mockito.Mockito.when;
-
-import android.os.RemoteException;
-import android.platform.test.annotations.Presubmit;
-
-import org.junit.Before;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.mockito.Mock;
-import org.mockito.MockitoAnnotations;
-import org.robolectric.RobolectricTestRunner;
-
-/**
- * Unit tests for {@link GnssGeofenceProvider}.
- */
-@RunWith(RobolectricTestRunner.class)
-@Presubmit
-public class GnssGeofenceProviderTest {
- private static final int GEOFENCE_ID = 12345;
- private static final double LATITUDE = 10.0;
- private static final double LONGITUDE = 20.0;
- private static final double RADIUS = 5.0;
- private static final int LAST_TRANSITION = 0;
- private static final int MONITOR_TRANSITIONS = 0;
- private static final int NOTIFICATION_RESPONSIVENESS = 0;
- private static final int UNKNOWN_TIMER = 0;
- @Mock
- private GnssGeofenceProvider.GnssGeofenceProviderNative mMockNative;
- private GnssGeofenceProvider mTestProvider;
-
- /**
- * Mocks native methods and adds a geofence to the GnssGeofenceProvider.
- */
- @Before
- public void setUp() {
- MockitoAnnotations.initMocks(this);
- when(mMockNative.addGeofence(anyInt(), anyDouble(), anyDouble(), anyDouble(), anyInt(),
- anyInt(), anyInt(), anyInt())).thenReturn(true);
- when(mMockNative.pauseGeofence(anyInt())).thenReturn(true);
- when(mMockNative.removeGeofence(anyInt())).thenReturn(true);
- when(mMockNative.resumeGeofence(anyInt(), anyInt())).thenReturn(true);
- mTestProvider = new GnssGeofenceProvider(mMockNative);
- mTestProvider.addCircularHardwareGeofence(GEOFENCE_ID, LATITUDE,
- LONGITUDE, RADIUS, LAST_TRANSITION, MONITOR_TRANSITIONS,
- NOTIFICATION_RESPONSIVENESS,
- UNKNOWN_TIMER);
- }
-
- /**
- * Verify native add geofence method is called.
- */
- @Test
- public void addGeofence_nativeAdded() {
- verify(mMockNative).addGeofence(eq(GEOFENCE_ID), eq(LATITUDE), eq(LONGITUDE),
- eq(RADIUS), eq(LAST_TRANSITION), eq(MONITOR_TRANSITIONS),
- eq(NOTIFICATION_RESPONSIVENESS),
- eq(UNKNOWN_TIMER));
- }
-
- /**
- * Verify pauseHardwareGeofence calls native pauseGeofence method.
- */
- @Test
- public void pauseGeofence_nativePaused() {
- mTestProvider.pauseHardwareGeofence(GEOFENCE_ID);
- verify(mMockNative).pauseGeofence(eq(GEOFENCE_ID));
- }
-
- /**
- * Verify removeHardwareGeofence calls native removeGeofence method.
- */
- @Test
- public void removeGeofence_nativeRemoved() {
- mTestProvider.removeHardwareGeofence(GEOFENCE_ID);
- verify(mMockNative).removeGeofence(eq(GEOFENCE_ID));
- }
-
- /**
- * Verify resumeHardwareGeofence, called after pauseHardwareGeofence, will call native
- * resumeGeofence method.
- */
- @Test
- public void resumeGeofence_nativeResumed() {
- mTestProvider.pauseHardwareGeofence(GEOFENCE_ID);
- mTestProvider.resumeHardwareGeofence(GEOFENCE_ID, MONITOR_TRANSITIONS);
- verify(mMockNative).resumeGeofence(eq(GEOFENCE_ID), eq(MONITOR_TRANSITIONS));
- }
-
- /**
- * Verify resumeIfStarted method will re-add previously added geofences.
- */
- @Test
- public void addGeofence_restart_added() throws RemoteException {
- mTestProvider.resumeIfStarted();
-
- verify(mMockNative, times(2)).addGeofence(eq(GEOFENCE_ID), eq(LATITUDE), eq(LONGITUDE),
- eq(RADIUS), eq(LAST_TRANSITION), eq(MONITOR_TRANSITIONS),
- eq(NOTIFICATION_RESPONSIVENESS),
- eq(UNKNOWN_TIMER));
- }
-
- /**
- * Verify resumeIfStarted method will not re-add previously added geofences if they have been
- * removed.
- */
- @Test
- public void removeGeofence_restart_notAdded() throws RemoteException {
- mTestProvider.removeHardwareGeofence(GEOFENCE_ID);
- mTestProvider.resumeIfStarted();
-
- verify(mMockNative, times(1)).addGeofence(eq(GEOFENCE_ID), eq(LATITUDE), eq(LONGITUDE),
- eq(RADIUS), eq(LAST_TRANSITION), eq(MONITOR_TRANSITIONS),
- eq(NOTIFICATION_RESPONSIVENESS),
- eq(UNKNOWN_TIMER));
- }
-
- /**
- * Verify resumeIfStarted, called after pauseHardwareGeofence, will re-add previously added
- * geofences, and re-pause geofencing.
- */
- @Test
- public void pauseGeofence_restart_paused() throws RemoteException {
- mTestProvider.pauseHardwareGeofence(GEOFENCE_ID);
- mTestProvider.resumeIfStarted();
-
- verify(mMockNative, times(2)).addGeofence(eq(GEOFENCE_ID), eq(LATITUDE), eq(LONGITUDE),
- eq(RADIUS), eq(LAST_TRANSITION), eq(MONITOR_TRANSITIONS),
- eq(NOTIFICATION_RESPONSIVENESS),
- eq(UNKNOWN_TIMER));
- verify(mMockNative, times(2)).pauseGeofence(eq(GEOFENCE_ID));
- }
-}
diff --git a/services/robotests/src/com/android/server/location/gnss/GnssPositionModeTest.java b/services/robotests/src/com/android/server/location/gnss/GnssPositionModeTest.java
deleted file mode 100644
index e7d3e51..0000000
--- a/services/robotests/src/com/android/server/location/gnss/GnssPositionModeTest.java
+++ /dev/null
@@ -1,76 +0,0 @@
-/*
- * Copyright (C) 2020 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.server.location.gnss;
-
-import static com.google.common.truth.Truth.assertThat;
-
-import android.platform.test.annotations.Presubmit;
-
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.robolectric.RobolectricTestRunner;
-
-import java.util.HashSet;
-
-/**
- * Unit tests for {@link GnssPositionMode}.
- */
-@RunWith(RobolectricTestRunner.class)
-@Presubmit
-public class GnssPositionModeTest {
-
- private GnssPositionMode mPositionMode1 = createGnssPositionMode(0, 1000);
- private GnssPositionMode mPositionMode2 = createGnssPositionMode(0, 1000);
- private GnssPositionMode mPositionMode3 = createGnssPositionMode(1, 1000);
-
- /**
- * Verifies hashcode method.
- */
- @Test
- public void testHashCode() {
- assertThat(mPositionMode1.hashCode()).isEqualTo(mPositionMode2.hashCode());
- assertThat(mPositionMode1.hashCode()).isNotEqualTo(mPositionMode3.hashCode());
- assertThat(mPositionMode1.hashCode()).isNotEqualTo(mPositionMode3.hashCode());
-
- HashSet<Integer> hashSet = new HashSet<>();
- hashSet.add(mPositionMode1.hashCode());
- hashSet.add(mPositionMode2.hashCode());
- assertThat(hashSet.size()).isEqualTo(1);
- hashSet.add(mPositionMode3.hashCode());
- assertThat(hashSet.size()).isEqualTo(2);
- }
-
- /**
- * Verify that GnssPositionMode objects that return true for equals() also have the same
- * hashcode.
- */
- @Test
- public void checkIfEqualsImpliesSameHashCode() {
- assertTEqualsImpliesSameHashCode(mPositionMode1, mPositionMode2);
- assertTEqualsImpliesSameHashCode(mPositionMode2, mPositionMode3);
- }
-
- private void assertTEqualsImpliesSameHashCode(GnssPositionMode mode1, GnssPositionMode mode2) {
- if (mode1.equals(mode2)) {
- assertThat(mode1.hashCode()).isEqualTo(mode2.hashCode());
- }
- }
-
- private GnssPositionMode createGnssPositionMode(int mode, int minInterval) {
- return new GnssPositionMode(mode, 0, minInterval, 0, 0, true);
- }
-}
diff --git a/services/tests/mockingservicestests/src/com/android/server/job/controllers/QuotaControllerTest.java b/services/tests/mockingservicestests/src/com/android/server/job/controllers/QuotaControllerTest.java
index 344a19a..05f1ed8 100644
--- a/services/tests/mockingservicestests/src/com/android/server/job/controllers/QuotaControllerTest.java
+++ b/services/tests/mockingservicestests/src/com/android/server/job/controllers/QuotaControllerTest.java
@@ -209,7 +209,8 @@
ArgumentCaptor.forClass(BroadcastReceiver.class);
ArgumentCaptor<IUidObserver> uidObserverCaptor =
ArgumentCaptor.forClass(IUidObserver.class);
- mQuotaController = new QuotaController(mJobSchedulerService);
+ mQuotaController = new QuotaController(mJobSchedulerService,
+ mock(BackgroundJobsController.class), mock(ConnectivityController.class));
verify(mContext).registerReceiver(receiverCaptor.capture(), any());
mChargingReceiver = receiverCaptor.getValue();
diff --git a/services/tests/mockingservicestests/src/com/android/server/location/gnss/GnssGeofenceProxyTest.java b/services/tests/mockingservicestests/src/com/android/server/location/gnss/GnssGeofenceProxyTest.java
new file mode 100644
index 0000000..b480f24
--- /dev/null
+++ b/services/tests/mockingservicestests/src/com/android/server/location/gnss/GnssGeofenceProxyTest.java
@@ -0,0 +1,134 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.location.gnss;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import android.platform.test.annotations.Presubmit;
+
+import androidx.test.filters.SmallTest;
+import androidx.test.runner.AndroidJUnit4;
+
+import com.android.server.location.gnss.hal.FakeGnssHal;
+import com.android.server.location.gnss.hal.GnssNative;
+import com.android.server.location.injector.TestInjector;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+
+import java.util.Objects;
+
+@Presubmit
+@SmallTest
+@RunWith(AndroidJUnit4.class)
+public class GnssGeofenceProxyTest {
+
+ private static final int GEOFENCE_ID = 12345;
+ private static final double LATITUDE = 10.0;
+ private static final double LONGITUDE = 20.0;
+ private static final double RADIUS = 5.0;
+ private static final int LAST_TRANSITION = 0;
+ private static final int MONITOR_TRANSITIONS = 0;
+ private static final int NOTIFICATION_RESPONSIVENESS = 0;
+ private static final int UNKNOWN_TIMER = 0;
+
+ private @Mock GnssConfiguration mMockConfiguration;
+ private @Mock GnssNative.GeofenceCallbacks mGeofenceCallbacks;
+
+ private FakeGnssHal mFakeHal;
+ private GnssGeofenceProxy mTestProvider;
+
+ @Before
+ public void setUp() {
+ MockitoAnnotations.initMocks(this);
+
+ mFakeHal = new FakeGnssHal();
+ GnssNative.setGnssHalForTest(mFakeHal);
+
+ GnssNative gnssNative = Objects.requireNonNull(
+ GnssNative.create(new TestInjector(), mMockConfiguration));
+ gnssNative.setGeofenceCallbacks(mGeofenceCallbacks);
+ mTestProvider = new GnssGeofenceProxy(gnssNative);
+ gnssNative.register();
+
+ mTestProvider.addCircularHardwareGeofence(GEOFENCE_ID, LATITUDE, LONGITUDE, RADIUS,
+ LAST_TRANSITION, MONITOR_TRANSITIONS, NOTIFICATION_RESPONSIVENESS, UNKNOWN_TIMER);
+ }
+
+ @Test
+ public void testAddGeofence() {
+ assertThat(mFakeHal.getGeofences()).containsExactly(new FakeGnssHal.GnssHalGeofence(
+ GEOFENCE_ID, LATITUDE, LONGITUDE, RADIUS, LAST_TRANSITION, MONITOR_TRANSITIONS,
+ NOTIFICATION_RESPONSIVENESS, UNKNOWN_TIMER, false));
+ }
+
+ @Test
+ public void testRemoveGeofence() {
+ mTestProvider.removeHardwareGeofence(GEOFENCE_ID);
+
+ assertThat(mFakeHal.getGeofences()).isEmpty();
+ }
+
+ @Test
+ public void testPauseGeofence() {
+ mTestProvider.pauseHardwareGeofence(GEOFENCE_ID);
+
+ assertThat(mFakeHal.getGeofences()).containsExactly(new FakeGnssHal.GnssHalGeofence(
+ GEOFENCE_ID, LATITUDE, LONGITUDE, RADIUS, LAST_TRANSITION, MONITOR_TRANSITIONS,
+ NOTIFICATION_RESPONSIVENESS, UNKNOWN_TIMER, true));
+ }
+
+ @Test
+ public void testResumeGeofence() {
+ mTestProvider.pauseHardwareGeofence(GEOFENCE_ID);
+ mTestProvider.resumeHardwareGeofence(GEOFENCE_ID, MONITOR_TRANSITIONS);
+
+ assertThat(mFakeHal.getGeofences()).containsExactly(new FakeGnssHal.GnssHalGeofence(
+ GEOFENCE_ID, LATITUDE, LONGITUDE, RADIUS, LAST_TRANSITION, MONITOR_TRANSITIONS,
+ NOTIFICATION_RESPONSIVENESS, UNKNOWN_TIMER, false));
+ }
+
+ @Test
+ public void testAddGeofence_restart() {
+ mFakeHal.restartHal();
+
+ assertThat(mFakeHal.getGeofences()).containsExactly(new FakeGnssHal.GnssHalGeofence(
+ GEOFENCE_ID, LATITUDE, LONGITUDE, RADIUS, LAST_TRANSITION, MONITOR_TRANSITIONS,
+ NOTIFICATION_RESPONSIVENESS, UNKNOWN_TIMER, false));
+ }
+
+ @Test
+ public void testRemoveGeofence_restart() {
+ mTestProvider.removeHardwareGeofence(GEOFENCE_ID);
+ mFakeHal.restartHal();
+
+ assertThat(mFakeHal.getGeofences()).isEmpty();
+ }
+
+ @Test
+ public void testPauseGeofence_restart() {
+ mTestProvider.pauseHardwareGeofence(GEOFENCE_ID);
+ mFakeHal.restartHal();
+
+ assertThat(mFakeHal.getGeofences()).containsExactly(new FakeGnssHal.GnssHalGeofence(
+ GEOFENCE_ID, LATITUDE, LONGITUDE, RADIUS, LAST_TRANSITION, MONITOR_TRANSITIONS,
+ NOTIFICATION_RESPONSIVENESS, UNKNOWN_TIMER, true));
+ }
+}
diff --git a/services/tests/mockingservicestests/src/com/android/server/location/gnss/GnssManagerServiceTest.java b/services/tests/mockingservicestests/src/com/android/server/location/gnss/GnssManagerServiceTest.java
deleted file mode 100644
index 2b21cc5..0000000
--- a/services/tests/mockingservicestests/src/com/android/server/location/gnss/GnssManagerServiceTest.java
+++ /dev/null
@@ -1,682 +0,0 @@
-/*
- * Copyright (C) 2020 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.server.location.gnss;
-
-import static android.app.AppOpsManager.OP_COARSE_LOCATION;
-import static android.app.AppOpsManager.OP_FINE_LOCATION;
-import static android.location.LocationManager.GPS_PROVIDER;
-
-import static com.google.common.truth.Truth.assertThat;
-
-import static org.mockito.ArgumentMatchers.any;
-import static org.mockito.ArgumentMatchers.anyInt;
-import static org.mockito.ArgumentMatchers.anyLong;
-import static org.mockito.ArgumentMatchers.anyString;
-import static org.mockito.ArgumentMatchers.eq;
-import static org.mockito.ArgumentMatchers.nullable;
-import static org.mockito.Mockito.after;
-import static org.mockito.Mockito.mock;
-import static org.mockito.Mockito.timeout;
-import static org.mockito.Mockito.times;
-import static org.mockito.Mockito.verify;
-import static org.mockito.Mockito.when;
-import static org.testng.Assert.assertThrows;
-
-import android.Manifest;
-import android.content.Context;
-import android.content.pm.PackageManager;
-import android.location.GnssAntennaInfo;
-import android.location.GnssAntennaInfo.SphericalCorrections;
-import android.location.GnssClock;
-import android.location.GnssMeasurementCorrections;
-import android.location.GnssMeasurementRequest;
-import android.location.GnssMeasurementsEvent;
-import android.location.GnssNavigationMessage;
-import android.location.GnssSingleSatCorrection;
-import android.location.IGnssAntennaInfoListener;
-import android.location.IGnssMeasurementsListener;
-import android.location.IGnssNavigationMessageListener;
-import android.location.IGnssStatusListener;
-import android.location.INetInitiatedListener;
-import android.location.LocationManagerInternal;
-import android.os.Handler;
-import android.os.IBinder;
-import android.os.IInterface;
-import android.os.Message;
-import android.os.RemoteException;
-
-import com.android.server.LocalServices;
-import com.android.server.location.gnss.GnssAntennaInfoProvider.GnssAntennaInfoProviderNative;
-import com.android.server.location.gnss.GnssMeasurementsProvider.GnssMeasurementProviderNative;
-import com.android.server.location.gnss.GnssNavigationMessageProvider.GnssNavigationMessageProviderNative;
-import com.android.server.location.injector.TestInjector;
-
-import org.junit.After;
-import org.junit.Before;
-import org.junit.Test;
-import org.mockito.AdditionalMatchers;
-import org.mockito.Mock;
-import org.mockito.Mockito;
-import org.mockito.MockitoAnnotations;
-import org.mockito.invocation.InvocationOnMock;
-
-import java.util.ArrayList;
-import java.util.Collections;
-import java.util.List;
-
-/**
- * Unit tests for {@link com.android.server.location.gnss.GnssManagerService}.
- */
-public class GnssManagerServiceTest {
-
- private static final long TIMEOUT_MS = 5000;
- private static final long FAILURE_TIMEOUT_MS = 200;
-
- private static final String TEST_PACKAGE = "com.test";
-
- private TestInjector mInjector;
-
- @Mock private Handler mMockHandler;
- @Mock private Context mMockContext;
- @Mock private PackageManager mPackageManager;
- @Mock private LocationManagerInternal mLocationManagerInternal;
- @Mock private GnssNative.GnssNativeInitNative mGnssInitNative;
- @Mock private GnssLocationProvider mMockGnssLocationProvider;
- @Mock private GnssLocationProvider.GnssSystemInfoProvider mMockGnssSystemInfoProvider;
- @Mock private GnssCapabilitiesProvider mMockGnssCapabilitiesProvider;
- @Mock private GnssMeasurementCorrectionsProvider mMockGnssMeasurementCorrectionsProvider;
- @Mock private INetInitiatedListener mNetInitiatedListener;
-
- private GnssMeasurementsProvider mTestGnssMeasurementsProvider;
- private GnssStatusProvider mTestGnssStatusProvider;
- private GnssNavigationMessageProvider mTestGnssNavigationMessageProvider;
- private GnssAntennaInfoProvider mTestGnssAntennaInfoProvider;
-
- private GnssManagerService mGnssManagerService;
-
- @Before
- public void setUp() {
- MockitoAnnotations.initMocks(this);
-
- when(mGnssInitNative.isSupported()).thenReturn(true);
- GnssNative.setInitNativeForTest(mGnssInitNative);
- GnssNative.resetCallbacksForTest();
-
- when(mMockContext.createAttributionContext(anyString())).thenReturn(mMockContext);
- when(mMockContext.getPackageManager()).thenReturn(mPackageManager);
- when(mPackageManager.getPackagesForUid(anyInt())).thenReturn(
- new String[]{TEST_PACKAGE});
-
- mInjector = new TestInjector();
-
- enableLocationPermissions();
-
- LocalServices.addService(LocationManagerInternal.class, mLocationManagerInternal);
-
- // Mock Handler will execute posted runnables immediately
- when(mMockHandler.sendMessageAtTime(any(Message.class), anyLong())).thenAnswer(
- (InvocationOnMock invocation) -> {
- Message msg = (Message) (invocation.getArguments()[0]);
- msg.getCallback().run();
- return null;
- });
-
- // Setup providers
- mTestGnssMeasurementsProvider = createGnssMeasurementsProvider();
- mTestGnssStatusProvider = createGnssStatusListenerHelper();
- mTestGnssNavigationMessageProvider = createGnssNavigationMessageProvider();
- mTestGnssAntennaInfoProvider = createGnssAntennaInfoProvider();
-
- // Setup GnssLocationProvider to return providers
- when(mMockGnssLocationProvider.getGnssStatusProvider()).thenReturn(
- mTestGnssStatusProvider);
- when(mMockGnssLocationProvider.getGnssCapabilitiesProvider()).thenReturn(
- mMockGnssCapabilitiesProvider);
- when(mMockGnssLocationProvider.getGnssSystemInfoProvider()).thenReturn(
- mMockGnssSystemInfoProvider);
- when(mMockGnssLocationProvider.getGnssMeasurementCorrectionsProvider()).thenReturn(
- mMockGnssMeasurementCorrectionsProvider);
- when(mMockGnssLocationProvider.getGnssMeasurementsProvider()).thenReturn(
- mTestGnssMeasurementsProvider);
- when(mMockGnssLocationProvider.getGnssNavigationMessageProvider()).thenReturn(
- mTestGnssNavigationMessageProvider);
- when(mMockGnssLocationProvider.getNetInitiatedListener()).thenReturn(
- mNetInitiatedListener);
- when(mMockGnssLocationProvider.getGnssAntennaInfoProvider()).thenReturn(
- mTestGnssAntennaInfoProvider);
-
- // Create GnssManagerService
- mGnssManagerService = new GnssManagerService(mMockContext, mInjector,
- mMockGnssLocationProvider);
- mGnssManagerService.onSystemReady();
- }
-
- @After
- public void tearDown() {
- LocalServices.removeServiceForTest(LocationManagerInternal.class);
- }
-
- private void overrideAsBinder(IInterface mockListener) {
- IBinder mockBinder = mock(IBinder.class);
- when(mockListener.asBinder()).thenReturn(mockBinder);
- }
-
- private IGnssStatusListener createMockGnssStatusListener() {
- IGnssStatusListener mockListener = mock(IGnssStatusListener.class);
- overrideAsBinder(mockListener);
- return mockListener;
- }
-
- private IGnssMeasurementsListener createMockGnssMeasurementsListener() {
- IGnssMeasurementsListener mockListener = mock(
- IGnssMeasurementsListener.class);
- overrideAsBinder(mockListener);
- return mockListener;
- }
-
- private IGnssAntennaInfoListener createMockGnssAntennaInfoListener() {
- IGnssAntennaInfoListener mockListener = mock(IGnssAntennaInfoListener.class);
- overrideAsBinder(mockListener);
- return mockListener;
- }
-
- private IGnssNavigationMessageListener createMockGnssNavigationMessageListener() {
- IGnssNavigationMessageListener mockListener = mock(IGnssNavigationMessageListener.class);
- overrideAsBinder(mockListener);
- return mockListener;
- }
-
- private GnssMeasurementCorrections createDummyGnssMeasurementCorrections() {
- GnssSingleSatCorrection gnssSingleSatCorrection =
- new GnssSingleSatCorrection.Builder().build();
- return
- new GnssMeasurementCorrections.Builder().setSingleSatelliteCorrectionList(
- Collections.singletonList(gnssSingleSatCorrection)).build();
- }
-
- private static List<GnssAntennaInfo> createDummyGnssAntennaInfos() {
- double carrierFrequencyMHz = 13758.0;
-
- GnssAntennaInfo.PhaseCenterOffset phaseCenterOffset = new
- GnssAntennaInfo.PhaseCenterOffset(
- 4.3d,
- 1.4d,
- 2.10d,
- 2.1d,
- 3.12d,
- 0.5d);
-
- double[][] phaseCenterVariationCorrectionsMillimeters = new double[10][10];
- double[][] phaseCenterVariationCorrectionsUncertaintyMillimeters = new double[10][10];
- SphericalCorrections
- phaseCenterVariationCorrections =
- new SphericalCorrections(
- phaseCenterVariationCorrectionsMillimeters,
- phaseCenterVariationCorrectionsUncertaintyMillimeters);
-
- double[][] signalGainCorrectionsDbi = new double[10][10];
- double[][] signalGainCorrectionsUncertaintyDbi = new double[10][10];
- SphericalCorrections signalGainCorrections = new
- SphericalCorrections(
- signalGainCorrectionsDbi,
- signalGainCorrectionsUncertaintyDbi);
-
- List<GnssAntennaInfo> gnssAntennaInfos = new ArrayList<>();
- gnssAntennaInfos.add(new GnssAntennaInfo.Builder()
- .setCarrierFrequencyMHz(carrierFrequencyMHz)
- .setPhaseCenterOffset(phaseCenterOffset)
- .setPhaseCenterVariationCorrections(phaseCenterVariationCorrections)
- .setSignalGainCorrections(signalGainCorrections)
- .build());
- return gnssAntennaInfos;
- }
-
- private void enableLocationPermissions() {
- Mockito.doThrow(new SecurityException()).when(
- mMockContext).enforceCallingOrSelfPermission(
- AdditionalMatchers.and(
- AdditionalMatchers.not(eq(Manifest.permission.LOCATION_HARDWARE)),
- AdditionalMatchers.not(eq(Manifest.permission.ACCESS_FINE_LOCATION))),
- anyString());
- when(mMockContext.checkPermission(
- eq(android.Manifest.permission.LOCATION_HARDWARE), anyInt(), anyInt())).thenReturn(
- PackageManager.PERMISSION_GRANTED);
- when(mMockContext.checkPermission(
- eq(Manifest.permission.ACCESS_FINE_LOCATION), anyInt(), anyInt())).thenReturn(
- PackageManager.PERMISSION_GRANTED);
- when(mMockContext.checkPermission(
- eq(Manifest.permission.ACCESS_COARSE_LOCATION), anyInt(), anyInt())).thenReturn(
- PackageManager.PERMISSION_GRANTED);
-
- mInjector.getAppOpsHelper().setAppOpAllowed(OP_FINE_LOCATION, TEST_PACKAGE, true);
- mInjector.getAppOpsHelper().setAppOpAllowed(OP_COARSE_LOCATION, TEST_PACKAGE, true);
-
- when(mLocationManagerInternal.isProviderEnabledForUser(eq(GPS_PROVIDER), anyInt()))
- .thenReturn(true);
- }
-
- private void disableLocationPermissions() {
- Mockito.doThrow(new SecurityException()).when(
- mMockContext).enforceCallingOrSelfPermission(anyString(), nullable(String.class));
-
- when(mMockContext.checkPermission(
- anyString(), anyInt(), anyInt())).thenReturn(
- PackageManager.PERMISSION_DENIED);
-
- mInjector.getAppOpsHelper().setAppOpAllowed(OP_FINE_LOCATION, TEST_PACKAGE, false);
- mInjector.getAppOpsHelper().setAppOpAllowed(OP_COARSE_LOCATION, TEST_PACKAGE, false);
-
- when(mLocationManagerInternal.isProviderEnabledForUser(eq(GPS_PROVIDER), anyInt()))
- .thenReturn(false);
- }
-
- private GnssStatusProvider createGnssStatusListenerHelper() {
- return new GnssStatusProvider(mInjector);
- }
-
- private GnssMeasurementsProvider createGnssMeasurementsProvider() {
- GnssMeasurementProviderNative
- mockGnssMeasurementProviderNative = mock(GnssMeasurementProviderNative.class);
- when(mockGnssMeasurementProviderNative.isMeasurementSupported()).thenReturn(
- true);
- return new GnssMeasurementsProvider(mInjector, mockGnssMeasurementProviderNative);
- }
-
- private GnssNavigationMessageProvider createGnssNavigationMessageProvider() {
- GnssNavigationMessageProviderNative mockGnssNavigationMessageProviderNative = mock(
- GnssNavigationMessageProviderNative.class);
- when(mockGnssNavigationMessageProviderNative.isNavigationMessageSupported()).thenReturn(
- true);
- return new GnssNavigationMessageProvider(mInjector,
- mockGnssNavigationMessageProviderNative);
- }
-
- private GnssAntennaInfoProvider createGnssAntennaInfoProvider() {
- GnssAntennaInfoProviderNative mockGnssAntenaInfoProviderNative = mock(
- GnssAntennaInfoProviderNative.class);
- when(mockGnssAntenaInfoProviderNative.isAntennaInfoSupported()).thenReturn(
- true);
- return new GnssAntennaInfoProvider(mInjector, mockGnssAntenaInfoProviderNative);
- }
-
- @Test
- public void getGnssYearOfHardwareTest() {
- final int gnssYearOfHardware = 2012;
- when(mMockGnssSystemInfoProvider.getGnssYearOfHardware()).thenReturn(gnssYearOfHardware);
- enableLocationPermissions();
-
- assertThat(mGnssManagerService.getGnssYearOfHardware()).isEqualTo(gnssYearOfHardware);
- }
-
- @Test
- public void getGnssHardwareModelNameTest() {
- final String gnssHardwareModelName = "hardwarename";
- when(mMockGnssSystemInfoProvider.getGnssHardwareModelName()).thenReturn(
- gnssHardwareModelName);
- enableLocationPermissions();
-
- assertThat(mGnssManagerService.getGnssHardwareModelName()).isEqualTo(
- gnssHardwareModelName);
- }
-
- @Test
- public void getGnssCapabilitiesWithPermissionsTest() {
- final long mGnssCapabilities = 23132L;
- when(mMockGnssCapabilitiesProvider.getGnssCapabilities()).thenReturn(mGnssCapabilities);
- enableLocationPermissions();
-
- assertThat(mGnssManagerService.getGnssCapabilities()).isEqualTo(mGnssCapabilities);
- }
-
- @Test
- public void registerGnssStatusCallbackWithoutPermissionsTest() throws RemoteException {
- final int timeToFirstFix = 20000;
- IGnssStatusListener mockGnssStatusListener = createMockGnssStatusListener();
-
- disableLocationPermissions();
-
- assertThrows(SecurityException.class, () -> mGnssManagerService
- .registerGnssStatusCallback(
- mockGnssStatusListener, TEST_PACKAGE, "abcd123"));
-
- mTestGnssStatusProvider.onFirstFix(timeToFirstFix);
-
- verify(mockGnssStatusListener, after(FAILURE_TIMEOUT_MS).times(0)).onFirstFix(
- timeToFirstFix);
- }
-
- @Test
- public void registerGnssStatusCallbackWithPermissionsTest() throws RemoteException {
- final int timeToFirstFix = 20000;
- IGnssStatusListener mockGnssStatusListener = createMockGnssStatusListener();
-
- enableLocationPermissions();
-
- mGnssManagerService.registerGnssStatusCallback(
- mockGnssStatusListener, TEST_PACKAGE, "abcd123");
-
- mTestGnssStatusProvider.onFirstFix(timeToFirstFix);
-
- verify(mockGnssStatusListener, timeout(TIMEOUT_MS).times(1)).onFirstFix(timeToFirstFix);
- }
-
- @Test
- public void unregisterGnssStatusCallbackWithPermissionsTest() throws RemoteException {
- final int timeToFirstFix = 20000;
- IGnssStatusListener mockGnssStatusListener = createMockGnssStatusListener();
-
- enableLocationPermissions();
-
- mGnssManagerService.registerGnssStatusCallback(
- mockGnssStatusListener, TEST_PACKAGE, "abcd123");
-
- mGnssManagerService.unregisterGnssStatusCallback(mockGnssStatusListener);
-
- mTestGnssStatusProvider.onFirstFix(timeToFirstFix);
-
- verify(mockGnssStatusListener, after(FAILURE_TIMEOUT_MS).times(0)).onFirstFix(
- timeToFirstFix);
- }
-
- @Test
- public void addGnssMeasurementsListenerWithoutPermissionsTest() throws RemoteException {
- IGnssMeasurementsListener mockGnssMeasurementsListener =
- createMockGnssMeasurementsListener();
- GnssMeasurementsEvent gnssMeasurementsEvent = new GnssMeasurementsEvent(new GnssClock(),
- null);
-
- disableLocationPermissions();
-
- assertThrows(SecurityException.class,
- () -> mGnssManagerService.addGnssMeasurementsListener(
- new GnssMeasurementRequest.Builder().build(), mockGnssMeasurementsListener,
- TEST_PACKAGE, null));
-
- mTestGnssMeasurementsProvider.onMeasurementsAvailable(gnssMeasurementsEvent);
- verify(mockGnssMeasurementsListener,
- after(FAILURE_TIMEOUT_MS).times(0)).onGnssMeasurementsReceived(
- gnssMeasurementsEvent);
- }
-
- @Test
- public void addGnssMeasurementsListenerWithPermissionsTest() throws RemoteException {
- IGnssMeasurementsListener mockGnssMeasurementsListener =
- createMockGnssMeasurementsListener();
- GnssMeasurementsEvent gnssMeasurementsEvent = new GnssMeasurementsEvent(new GnssClock(),
- null);
-
- enableLocationPermissions();
-
- mGnssManagerService.addGnssMeasurementsListener(
- new GnssMeasurementRequest.Builder().build(),
- mockGnssMeasurementsListener,
- TEST_PACKAGE, null);
-
- mTestGnssMeasurementsProvider.onMeasurementsAvailable(gnssMeasurementsEvent);
- verify(mockGnssMeasurementsListener,
- timeout(TIMEOUT_MS).times(1)).onGnssMeasurementsReceived(
- gnssMeasurementsEvent);
- }
-
- @Test
- public void injectGnssMeasurementCorrectionsWithoutPermissionsTest() {
- GnssMeasurementCorrections gnssMeasurementCorrections =
- createDummyGnssMeasurementCorrections();
-
- disableLocationPermissions();
-
- assertThrows(SecurityException.class,
- () -> mGnssManagerService.injectGnssMeasurementCorrections(
- gnssMeasurementCorrections));
- verify(mMockGnssMeasurementCorrectionsProvider, times(0))
- .injectGnssMeasurementCorrections(
- gnssMeasurementCorrections);
- }
-
- @Test
- public void injectGnssMeasurementCorrectionsWithPermissionsTest() {
- GnssMeasurementCorrections gnssMeasurementCorrections =
- createDummyGnssMeasurementCorrections();
-
- enableLocationPermissions();
-
- mGnssManagerService.injectGnssMeasurementCorrections(
- gnssMeasurementCorrections);
- verify(mMockGnssMeasurementCorrectionsProvider, times(1))
- .injectGnssMeasurementCorrections(
- gnssMeasurementCorrections);
- }
-
- @Test
- public void removeGnssMeasurementsListenerWithoutPermissionsTest() throws RemoteException {
- IGnssMeasurementsListener mockGnssMeasurementsListener =
- createMockGnssMeasurementsListener();
- GnssMeasurementsEvent gnssMeasurementsEvent = new GnssMeasurementsEvent(new GnssClock(),
- null);
-
- enableLocationPermissions();
-
- mGnssManagerService.addGnssMeasurementsListener(
- new GnssMeasurementRequest.Builder().build(),
- mockGnssMeasurementsListener,
- TEST_PACKAGE, null);
-
- disableLocationPermissions();
-
- mGnssManagerService.removeGnssMeasurementsListener(
- mockGnssMeasurementsListener);
-
- mTestGnssMeasurementsProvider.onMeasurementsAvailable(gnssMeasurementsEvent);
- verify(mockGnssMeasurementsListener,
- after(FAILURE_TIMEOUT_MS).times(0)).onGnssMeasurementsReceived(
- gnssMeasurementsEvent);
- }
-
- @Test
- public void removeGnssMeasurementsListenerWithPermissionsTest() throws RemoteException {
- IGnssMeasurementsListener mockGnssMeasurementsListener =
- createMockGnssMeasurementsListener();
- GnssMeasurementsEvent gnssMeasurementsEvent = new GnssMeasurementsEvent(new GnssClock(),
- null);
-
- enableLocationPermissions();
-
- mGnssManagerService.addGnssMeasurementsListener(
- new GnssMeasurementRequest.Builder().build(),
- mockGnssMeasurementsListener,
- TEST_PACKAGE, null);
-
- disableLocationPermissions();
-
- mGnssManagerService.removeGnssMeasurementsListener(
- mockGnssMeasurementsListener);
-
- mTestGnssMeasurementsProvider.onMeasurementsAvailable(gnssMeasurementsEvent);
- verify(mockGnssMeasurementsListener,
- after(FAILURE_TIMEOUT_MS).times(0)).onGnssMeasurementsReceived(
- gnssMeasurementsEvent);
- }
-
- @Test
- public void addGnssAntennaInfoListenerWithoutPermissionsTest() throws RemoteException {
- IGnssAntennaInfoListener mockGnssAntennaInfoListener =
- createMockGnssAntennaInfoListener();
- List<GnssAntennaInfo> gnssAntennaInfos = createDummyGnssAntennaInfos();
-
- disableLocationPermissions();
-
- assertThrows(SecurityException.class,
- () -> mGnssManagerService.addGnssAntennaInfoListener(
- mockGnssAntennaInfoListener,
- TEST_PACKAGE, null));
-
- mTestGnssAntennaInfoProvider.onGnssAntennaInfoAvailable(gnssAntennaInfos);
- verify(mockGnssAntennaInfoListener, after(FAILURE_TIMEOUT_MS).times(0))
- .onGnssAntennaInfoReceived(gnssAntennaInfos);
- }
-
- @Test
- public void addGnssAntennaInfoListenerWithPermissionsTest() throws RemoteException {
- IGnssAntennaInfoListener mockGnssAntennaInfoListener =
- createMockGnssAntennaInfoListener();
- List<GnssAntennaInfo> gnssAntennaInfos = createDummyGnssAntennaInfos();
-
- enableLocationPermissions();
-
- mGnssManagerService.addGnssAntennaInfoListener(mockGnssAntennaInfoListener,
- TEST_PACKAGE, null);
-
- mTestGnssAntennaInfoProvider.onGnssAntennaInfoAvailable(gnssAntennaInfos);
- verify(mockGnssAntennaInfoListener, timeout(TIMEOUT_MS).times(1))
- .onGnssAntennaInfoReceived(gnssAntennaInfos);
- }
-
- @Test
- public void removeGnssAntennaInfoListenerWithoutPermissionsTest() throws RemoteException {
- IGnssAntennaInfoListener mockGnssAntennaInfoListener =
- createMockGnssAntennaInfoListener();
- List<GnssAntennaInfo> gnssAntennaInfos = createDummyGnssAntennaInfos();
-
- enableLocationPermissions();
-
- mGnssManagerService.addGnssAntennaInfoListener(
- mockGnssAntennaInfoListener,
- TEST_PACKAGE, null);
-
- disableLocationPermissions();
-
- mGnssManagerService.removeGnssAntennaInfoListener(
- mockGnssAntennaInfoListener);
-
- mTestGnssAntennaInfoProvider.onGnssAntennaInfoAvailable(gnssAntennaInfos);
- verify(mockGnssAntennaInfoListener, after(FAILURE_TIMEOUT_MS).times(0))
- .onGnssAntennaInfoReceived(gnssAntennaInfos);
- }
-
- @Test
- public void removeGnssAntennaInfoListenerWithPermissionsTest() throws RemoteException {
- IGnssAntennaInfoListener mockGnssAntennaInfoListener =
- createMockGnssAntennaInfoListener();
- List<GnssAntennaInfo> gnssAntennaInfos = createDummyGnssAntennaInfos();
-
- enableLocationPermissions();
-
- mGnssManagerService.addGnssAntennaInfoListener(
- mockGnssAntennaInfoListener,
- TEST_PACKAGE, null);
-
- mGnssManagerService.removeGnssAntennaInfoListener(
- mockGnssAntennaInfoListener);
-
- mTestGnssAntennaInfoProvider.onGnssAntennaInfoAvailable(gnssAntennaInfos);
- verify(mockGnssAntennaInfoListener,
- after(FAILURE_TIMEOUT_MS).times(0)).onGnssAntennaInfoReceived(
- gnssAntennaInfos);
- }
-
- @Test
- public void addGnssNavigationMessageListenerWithoutPermissionsTest() throws RemoteException {
- IGnssNavigationMessageListener mockGnssNavigationMessageListener =
- createMockGnssNavigationMessageListener();
- GnssNavigationMessage gnssNavigationMessage = new GnssNavigationMessage();
-
- disableLocationPermissions();
-
- assertThrows(SecurityException.class,
- () -> mGnssManagerService.addGnssNavigationMessageListener(
- mockGnssNavigationMessageListener, TEST_PACKAGE, null));
-
- mTestGnssNavigationMessageProvider.onNavigationMessageAvailable(gnssNavigationMessage);
-
- verify(mockGnssNavigationMessageListener,
- after(FAILURE_TIMEOUT_MS).times(0)).onGnssNavigationMessageReceived(
- gnssNavigationMessage);
- }
-
- @Test
- public void addGnssNavigationMessageListenerWithPermissionsTest() throws RemoteException {
- IGnssNavigationMessageListener mockGnssNavigationMessageListener =
- createMockGnssNavigationMessageListener();
- GnssNavigationMessage gnssNavigationMessage = new GnssNavigationMessage();
-
- enableLocationPermissions();
-
- mGnssManagerService.addGnssNavigationMessageListener(
- mockGnssNavigationMessageListener, TEST_PACKAGE, null);
-
- mTestGnssNavigationMessageProvider.onNavigationMessageAvailable(gnssNavigationMessage);
-
- verify(mockGnssNavigationMessageListener,
- timeout(TIMEOUT_MS).times(1)).onGnssNavigationMessageReceived(
- gnssNavigationMessage);
- }
-
- @Test
- public void removeGnssNavigationMessageListenerWithoutPermissionsTest() throws RemoteException {
- IGnssNavigationMessageListener mockGnssNavigationMessageListener =
- createMockGnssNavigationMessageListener();
- GnssNavigationMessage gnssNavigationMessage = new GnssNavigationMessage();
-
- enableLocationPermissions();
-
- mGnssManagerService.addGnssNavigationMessageListener(
- mockGnssNavigationMessageListener, TEST_PACKAGE, null);
-
- disableLocationPermissions();
-
- mGnssManagerService.removeGnssNavigationMessageListener(
- mockGnssNavigationMessageListener);
-
- mTestGnssNavigationMessageProvider.onNavigationMessageAvailable(gnssNavigationMessage);
-
- verify(mockGnssNavigationMessageListener,
- after(FAILURE_TIMEOUT_MS).times(0)).onGnssNavigationMessageReceived(
- gnssNavigationMessage);
- }
-
- @Test
- public void removeGnssNavigationMessageListenerWithPermissionsTest() throws RemoteException {
- IGnssNavigationMessageListener mockGnssNavigationMessageListener =
- createMockGnssNavigationMessageListener();
- GnssNavigationMessage gnssNavigationMessage = new GnssNavigationMessage();
-
- enableLocationPermissions();
-
- mGnssManagerService.addGnssNavigationMessageListener(
- mockGnssNavigationMessageListener, TEST_PACKAGE, null);
-
- mGnssManagerService.removeGnssNavigationMessageListener(
- mockGnssNavigationMessageListener);
-
- mTestGnssNavigationMessageProvider.onNavigationMessageAvailable(gnssNavigationMessage);
-
- verify(mockGnssNavigationMessageListener,
- after(FAILURE_TIMEOUT_MS).times(0)).onGnssNavigationMessageReceived(
- gnssNavigationMessage);
- }
-
- @Test
- public void sendNiResponseWithPermissionsTest() throws RemoteException {
- int notifId = 0;
- int userResponse = 0;
- enableLocationPermissions();
-
- mGnssManagerService.sendNiResponse(notifId, userResponse);
-
- verify(mNetInitiatedListener, times(1)).sendNiResponse(notifId, userResponse);
- }
-}
diff --git a/services/tests/mockingservicestests/src/com/android/server/location/gnss/hal/FakeGnssHal.java b/services/tests/mockingservicestests/src/com/android/server/location/gnss/hal/FakeGnssHal.java
new file mode 100644
index 0000000..675274b
--- /dev/null
+++ b/services/tests/mockingservicestests/src/com/android/server/location/gnss/hal/FakeGnssHal.java
@@ -0,0 +1,674 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.location.gnss.hal;
+
+import static com.android.server.location.gnss.hal.GnssNative.GNSS_LOCATION_HAS_ALTITUDE;
+import static com.android.server.location.gnss.hal.GnssNative.GNSS_LOCATION_HAS_BEARING;
+import static com.android.server.location.gnss.hal.GnssNative.GNSS_LOCATION_HAS_BEARING_ACCURACY;
+import static com.android.server.location.gnss.hal.GnssNative.GNSS_LOCATION_HAS_HORIZONTAL_ACCURACY;
+import static com.android.server.location.gnss.hal.GnssNative.GNSS_LOCATION_HAS_LAT_LONG;
+import static com.android.server.location.gnss.hal.GnssNative.GNSS_LOCATION_HAS_SPEED;
+import static com.android.server.location.gnss.hal.GnssNative.GNSS_LOCATION_HAS_SPEED_ACCURACY;
+import static com.android.server.location.gnss.hal.GnssNative.GNSS_LOCATION_HAS_VERTICAL_ACCURACY;
+import static com.android.server.location.gnss.hal.GnssNative.GNSS_REALTIME_HAS_TIMESTAMP_NS;
+import static com.android.server.location.gnss.hal.GnssNative.GNSS_REALTIME_HAS_TIME_UNCERTAINTY_NS;
+import static com.android.server.location.gnss.hal.GnssNative.GeofenceCallbacks.GEOFENCE_STATUS_ERROR_ID_EXISTS;
+import static com.android.server.location.gnss.hal.GnssNative.GeofenceCallbacks.GEOFENCE_STATUS_ERROR_ID_UNKNOWN;
+import static com.android.server.location.gnss.hal.GnssNative.GeofenceCallbacks.GEOFENCE_STATUS_OPERATION_SUCCESS;
+import static com.android.server.location.gnss.hal.GnssNative.GeofenceCallbacks.GEOFENCE_TRANSITION_ENTERED;
+import static com.android.server.location.gnss.hal.GnssNative.GeofenceCallbacks.GEOFENCE_TRANSITION_EXITED;
+
+import android.annotation.Nullable;
+import android.location.GnssAntennaInfo;
+import android.location.GnssMeasurementCorrections;
+import android.location.GnssMeasurementsEvent;
+import android.location.GnssNavigationMessage;
+import android.location.Location;
+
+import com.android.server.location.gnss.GnssPowerStats;
+import com.android.server.location.gnss.hal.GnssNative.GnssLocationFlags;
+import com.android.server.location.gnss.hal.GnssNative.GnssRealtimeFlags;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Objects;
+
+/**
+ * Fake GNSS HAL for testing.
+ */
+public final class FakeGnssHal extends GnssNative.GnssHal {
+
+ public static class GnssHalPositionMode {
+
+ public final int Mode;
+ public final int Recurrence;
+ public final int MinInterval;
+ public final int PreferredAccuracy;
+ public final int PreferredTime;
+ public final boolean LowPowerMode;
+
+ GnssHalPositionMode() {
+ Mode = 0;
+ Recurrence = 0;
+ MinInterval = 0;
+ PreferredAccuracy = 0;
+ PreferredTime = 0;
+ LowPowerMode = false;
+ }
+
+ public GnssHalPositionMode(int mode, int recurrence, int minInterval, int preferredAccuracy,
+ int preferredTime, boolean lowPowerMode) {
+ Mode = mode;
+ Recurrence = recurrence;
+ MinInterval = minInterval;
+ PreferredAccuracy = preferredAccuracy;
+ PreferredTime = preferredTime;
+ LowPowerMode = lowPowerMode;
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (this == o) {
+ return true;
+ }
+ if (o == null || getClass() != o.getClass()) {
+ return false;
+ }
+
+ GnssHalPositionMode that = (GnssHalPositionMode) o;
+ return Mode == that.Mode
+ && Recurrence == that.Recurrence
+ && MinInterval == that.MinInterval
+ && PreferredAccuracy == that.PreferredAccuracy
+ && PreferredTime == that.PreferredTime
+ && LowPowerMode == that.LowPowerMode;
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(Recurrence, MinInterval);
+ }
+ }
+
+ public static class GnssHalBatchingMode {
+
+ public final long PeriodNanos;
+ public final boolean WakeOnFifoFull;
+
+ GnssHalBatchingMode() {
+ PeriodNanos = 0;
+ WakeOnFifoFull = false;
+ }
+
+ public GnssHalBatchingMode(long periodNanos, boolean wakeOnFifoFull) {
+ PeriodNanos = periodNanos;
+ WakeOnFifoFull = wakeOnFifoFull;
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (this == o) {
+ return true;
+ }
+ if (o == null || getClass() != o.getClass()) {
+ return false;
+ }
+
+ GnssHalBatchingMode that = (GnssHalBatchingMode) o;
+ return PeriodNanos == that.PeriodNanos
+ && WakeOnFifoFull == that.WakeOnFifoFull;
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(PeriodNanos, WakeOnFifoFull);
+ }
+ }
+
+ public static class GnssHalInjectedTime {
+
+ public final long Time;
+ public final long TimeReference;
+ public final int Uncertainty;
+
+ public GnssHalInjectedTime(long time, long timeReference, int uncertainty) {
+ Time = time;
+ TimeReference = timeReference;
+ Uncertainty = uncertainty;
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (this == o) {
+ return true;
+ }
+ if (o == null || getClass() != o.getClass()) {
+ return false;
+ }
+
+ GnssHalInjectedTime that = (GnssHalInjectedTime) o;
+ return Time == that.Time
+ && TimeReference == that.TimeReference
+ && Uncertainty == that.Uncertainty;
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(Time);
+ }
+ }
+
+ public static class GnssHalGeofence {
+
+ public final int GeofenceId;
+ public final Location Center;
+ public final double Radius;
+ public int LastTransition;
+ public int MonitorTransitions;
+ public final int NotificationResponsiveness;
+ public final int UnknownTimer;
+ public boolean Paused;
+
+ public GnssHalGeofence(int geofenceId, double latitude, double longitude, double radius,
+ int lastTransition, int monitorTransitions, int notificationResponsiveness,
+ int unknownTimer, boolean paused) {
+ GeofenceId = geofenceId;
+ Center = new Location("");
+ Center.setLatitude(latitude);
+ Center.setLongitude(longitude);
+ Radius = radius;
+ LastTransition = lastTransition;
+ MonitorTransitions = monitorTransitions;
+ NotificationResponsiveness = notificationResponsiveness;
+ UnknownTimer = unknownTimer;
+ Paused = paused;
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (this == o) {
+ return true;
+ }
+ if (o == null || getClass() != o.getClass()) {
+ return false;
+ }
+
+ GnssHalGeofence that = (GnssHalGeofence) o;
+ return GeofenceId == that.GeofenceId
+ && Double.compare(that.Radius, Radius) == 0
+ && LastTransition == that.LastTransition
+ && MonitorTransitions == that.MonitorTransitions
+ && NotificationResponsiveness == that.NotificationResponsiveness
+ && UnknownTimer == that.UnknownTimer
+ && Paused == that.Paused
+ && Center.equals(that.Center);
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(GeofenceId);
+ }
+ }
+
+ private static class HalState {
+ private boolean mStarted = false;
+ private boolean mBatchingStarted = false;
+ private boolean mNavigationMessagesStarted = false;
+ private boolean mAntennaInfoListeningStarted = false;
+ private boolean mMeasurementCollectionStarted = false;
+ private boolean mMeasurementCollectionFullTracking = false;
+ private GnssHalPositionMode mPositionMode = new GnssHalPositionMode();
+ private GnssHalBatchingMode mBatchingMode = new GnssHalBatchingMode();
+ private final ArrayList<Location> mBatchedLocations = new ArrayList<>();
+ private Location mInjectedLocation = null;
+ private Location mInjectedBestLocation = null;
+ private GnssHalInjectedTime mInjectedTime = null;
+ private GnssMeasurementCorrections mInjectedMeasurementCorrections = null;
+ private final HashMap<Integer, GnssHalGeofence> mGeofences = new HashMap<>();
+ private GnssPowerStats mPowerStats = new GnssPowerStats(0, 0, 0, 0, 0, 0, 0, 0,
+ new double[0]);
+ }
+
+ private @Nullable GnssNative mGnssNative;
+ private HalState mState = new HalState();
+
+ private boolean mIsNavigationMessageCollectionSupported = true;
+ private boolean mIsAntennaInfoListeningSupported = true;
+ private boolean mIsMeasurementSupported = true;
+ private boolean mIsMeasurementCorrectionsSupported = true;
+ private int mBatchSize = 0;
+ private boolean mIsGeofencingSupported = true;
+ private boolean mIsVisibilityControlSupported = true;
+
+ public FakeGnssHal() {}
+
+ public void restartHal() {
+ mState = new HalState();
+ Objects.requireNonNull(mGnssNative).restartHal();
+ }
+
+ public void setIsNavigationMessageCollectionSupported(boolean supported) {
+ mIsNavigationMessageCollectionSupported = supported;
+ }
+
+ public void setIsAntennaInfoListeningSupported(boolean supported) {
+ mIsAntennaInfoListeningSupported = supported;
+ }
+
+ public void setIsMeasurementSupported(boolean supported) {
+ mIsMeasurementSupported = supported;
+ }
+
+ public void setIsMeasurementCorrectionsSupported(boolean supported) {
+ mIsMeasurementCorrectionsSupported = supported;
+ }
+
+ public void setBatchSize(int batchSize) {
+ mBatchSize = batchSize;
+ }
+
+ public void setIsGeofencingSupported(boolean supported) {
+ mIsGeofencingSupported = supported;
+ }
+
+ public void setPowerStats(GnssPowerStats powerStats) {
+ mState.mPowerStats = powerStats;
+ }
+
+ public void setIsVisibilityControlSupported(boolean supported) {
+ mIsVisibilityControlSupported = supported;
+ }
+
+ public GnssHalPositionMode getPositionMode() {
+ return mState.mPositionMode;
+ }
+
+ public void reportLocation(Location location) {
+ if (mState.mStarted) {
+ Objects.requireNonNull(mGnssNative).reportLocation(true, location);
+ }
+ if (mState.mBatchingStarted) {
+ mState.mBatchedLocations.add(location);
+ if (mState.mBatchedLocations.size() >= mBatchSize) {
+ if (mState.mBatchingMode.WakeOnFifoFull) {
+ flushBatch();
+ } else {
+ mState.mBatchedLocations.remove(0);
+ }
+ }
+ }
+ for (GnssHalGeofence geofence : mState.mGeofences.values()) {
+ if (!geofence.Paused) {
+ if (geofence.Center.distanceTo(location) > geofence.Radius) {
+ if (geofence.LastTransition != GEOFENCE_TRANSITION_EXITED) {
+ geofence.LastTransition = GEOFENCE_TRANSITION_EXITED;
+ if ((geofence.MonitorTransitions & GEOFENCE_TRANSITION_EXITED) != 0) {
+ Objects.requireNonNull(mGnssNative).reportGeofenceTransition(
+ geofence.GeofenceId, location, GEOFENCE_TRANSITION_EXITED,
+ location.getTime());
+ }
+ }
+ } else {
+ if (geofence.LastTransition != GEOFENCE_TRANSITION_ENTERED) {
+ geofence.LastTransition = GEOFENCE_TRANSITION_ENTERED;
+ if ((geofence.MonitorTransitions & GEOFENCE_TRANSITION_ENTERED) != 0) {
+ Objects.requireNonNull(mGnssNative).reportGeofenceTransition(
+ geofence.GeofenceId, location, GEOFENCE_TRANSITION_ENTERED,
+ location.getTime());
+ }
+ }
+ }
+ }
+ }
+ }
+
+ public void reportNavigationMessage(GnssNavigationMessage message) {
+ if (mState.mNavigationMessagesStarted) {
+ Objects.requireNonNull(mGnssNative).reportNavigationMessage(message);
+ }
+ }
+
+ public void reportAntennaInfo(List<GnssAntennaInfo> antennaInfos) {
+ if (mState.mAntennaInfoListeningStarted) {
+ Objects.requireNonNull(mGnssNative).reportAntennaInfo(antennaInfos);
+ }
+ }
+
+ public boolean isMeasurementCollectionFullTracking() {
+ return mState.mMeasurementCollectionFullTracking;
+ }
+
+ public void reportMeasurement(GnssMeasurementsEvent event) {
+ if (mState.mMeasurementCollectionStarted) {
+ Objects.requireNonNull(mGnssNative).reportMeasurementData(event);
+ }
+ }
+
+ public GnssHalInjectedTime getLastInjectedTime() {
+ return mState.mInjectedTime;
+ }
+
+ public GnssMeasurementCorrections getLastInjectedCorrections() {
+ return mState.mInjectedMeasurementCorrections;
+ }
+
+ public Collection<GnssHalGeofence> getGeofences() {
+ return mState.mGeofences.values();
+ }
+
+ @Override
+ protected void classInitOnce() {}
+
+ @Override
+ protected boolean isSupported() {
+ return true;
+ }
+
+ @Override
+ protected void initOnce(GnssNative gnssNative, boolean reinitializeGnssServiceHandle) {
+ mGnssNative = Objects.requireNonNull(gnssNative);
+ }
+
+ @Override
+ protected boolean init() {
+ return true;
+ }
+
+ @Override
+ protected void cleanup() {}
+
+ @Override
+ protected boolean start() {
+ mState.mStarted = true;
+ return true;
+ }
+
+ @Override
+ protected boolean stop() {
+ mState.mStarted = false;
+ return true;
+ }
+
+ @Override
+ protected boolean setPositionMode(int mode, int recurrence, int minInterval,
+ int preferredAccuracy, int preferredTime, boolean lowPowerMode) {
+ mState.mPositionMode = new GnssHalPositionMode(mode, recurrence, minInterval,
+ preferredAccuracy, preferredTime, lowPowerMode);
+ return true;
+ }
+
+ @Override
+ protected String getInternalState() {
+ return "DebugState";
+ }
+
+ @Override
+ protected void deleteAidingData(int flags) {}
+
+ @Override
+ protected int readNmea(byte[] buffer, int bufferSize) {
+ return 0;
+ }
+
+ @Override
+ protected void injectLocation(double latitude, double longitude, float accuracy) {
+ mState.mInjectedLocation = new Location("injected");
+ mState.mInjectedLocation.setLatitude(latitude);
+ mState.mInjectedLocation.setLongitude(longitude);
+ mState.mInjectedLocation.setAccuracy(accuracy);
+ }
+
+ @Override
+ protected void injectBestLocation(@GnssLocationFlags int gnssLocationFlags, double latitude,
+ double longitude, double altitude, float speed, float bearing, float horizontalAccuracy,
+ float verticalAccuracy, float speedAccuracy, float bearingAccuracy, long timestamp,
+ @GnssRealtimeFlags int elapsedRealtimeFlags, long elapsedRealtimeNanos,
+ double elapsedRealtimeUncertaintyNanos) {
+ mState.mInjectedBestLocation = new Location("injectedBest");
+ if ((gnssLocationFlags & GNSS_LOCATION_HAS_LAT_LONG) != 0) {
+ mState.mInjectedBestLocation.setLatitude(latitude);
+ mState.mInjectedBestLocation.setLongitude(longitude);
+ }
+ if ((gnssLocationFlags & GNSS_LOCATION_HAS_ALTITUDE) != 0) {
+ mState.mInjectedBestLocation.setAltitude(altitude);
+ }
+ if ((gnssLocationFlags & GNSS_LOCATION_HAS_SPEED) != 0) {
+ mState.mInjectedBestLocation.setSpeed(speed);
+ }
+ if ((gnssLocationFlags & GNSS_LOCATION_HAS_BEARING) != 0) {
+ mState.mInjectedBestLocation.setBearing(bearing);
+ }
+ if ((gnssLocationFlags & GNSS_LOCATION_HAS_HORIZONTAL_ACCURACY) != 0) {
+ mState.mInjectedBestLocation.setAccuracy(horizontalAccuracy);
+ }
+ if ((gnssLocationFlags & GNSS_LOCATION_HAS_VERTICAL_ACCURACY) != 0) {
+ mState.mInjectedBestLocation.setVerticalAccuracyMeters(verticalAccuracy);
+ }
+ if ((gnssLocationFlags & GNSS_LOCATION_HAS_SPEED_ACCURACY) != 0) {
+ mState.mInjectedBestLocation.setSpeedAccuracyMetersPerSecond(speedAccuracy);
+ }
+ if ((gnssLocationFlags & GNSS_LOCATION_HAS_BEARING_ACCURACY) != 0) {
+ mState.mInjectedBestLocation.setBearingAccuracyDegrees(bearingAccuracy);
+ }
+ mState.mInjectedBestLocation.setTime(timestamp);
+ if ((elapsedRealtimeFlags & GNSS_REALTIME_HAS_TIMESTAMP_NS) != 0) {
+ mState.mInjectedBestLocation.setElapsedRealtimeNanos(elapsedRealtimeNanos);
+ }
+ if ((elapsedRealtimeFlags & GNSS_REALTIME_HAS_TIME_UNCERTAINTY_NS) != 0) {
+ mState.mInjectedBestLocation.setElapsedRealtimeUncertaintyNanos(
+ elapsedRealtimeUncertaintyNanos);
+ }
+ }
+
+ @Override
+ protected void injectTime(long time, long timeReference, int uncertainty) {
+ mState.mInjectedTime = new GnssHalInjectedTime(time, timeReference, uncertainty);
+ }
+
+ @Override
+ protected boolean isNavigationMessageCollectionSupported() {
+ return mIsNavigationMessageCollectionSupported;
+ }
+
+ @Override
+ protected boolean startNavigationMessageCollection() {
+ mState.mNavigationMessagesStarted = true;
+ return true;
+ }
+
+ @Override
+ protected boolean stopNavigationMessageCollection() {
+ mState.mNavigationMessagesStarted = false;
+ return true;
+ }
+
+ @Override
+ protected boolean isAntennaInfoListeningSupported() {
+ return mIsAntennaInfoListeningSupported;
+ }
+
+ @Override
+ protected boolean startAntennaInfoListening() {
+ mState.mAntennaInfoListeningStarted = true;
+ return true;
+ }
+
+ @Override
+ protected boolean stopAntennaInfoListening() {
+ mState.mAntennaInfoListeningStarted = false;
+ return true;
+ }
+
+ @Override
+ protected boolean isMeasurementSupported() {
+ return mIsMeasurementSupported;
+ }
+
+ @Override
+ protected boolean startMeasurementCollection(boolean enableFullTracking) {
+ mState.mMeasurementCollectionStarted = true;
+ mState.mMeasurementCollectionFullTracking = enableFullTracking;
+ return true;
+ }
+
+ @Override
+ protected boolean stopMeasurementCollection() {
+ mState.mMeasurementCollectionStarted = false;
+ mState.mMeasurementCollectionFullTracking = false;
+ return true;
+ }
+
+ @Override
+ protected boolean isMeasurementCorrectionsSupported() {
+ return mIsMeasurementCorrectionsSupported;
+ }
+
+ @Override
+ protected boolean injectMeasurementCorrections(GnssMeasurementCorrections corrections) {
+ mState.mInjectedMeasurementCorrections = corrections;
+ return true;
+ }
+
+ @Override
+ protected int getBatchSize() {
+ return mBatchSize;
+ }
+
+ @Override
+ protected boolean initBatching() {
+ return true;
+ }
+
+ @Override
+ protected void cleanupBatching() {}
+
+ @Override
+ protected boolean startBatch(long periodNanos, boolean wakeOnFifoFull) {
+ mState.mBatchingStarted = true;
+ mState.mBatchingMode = new GnssHalBatchingMode(periodNanos, wakeOnFifoFull);
+ return true;
+ }
+
+ @Override
+ protected void flushBatch() {
+ Location[] locations = mState.mBatchedLocations.toArray(new Location[0]);
+ mState.mBatchedLocations.clear();
+ Objects.requireNonNull(mGnssNative).reportLocationBatch(locations);
+ }
+
+ @Override
+ protected void stopBatch() {
+ mState.mBatchingStarted = false;
+ mState.mBatchingMode = new GnssHalBatchingMode();
+ mState.mBatchedLocations.clear();
+ }
+
+ @Override
+ protected boolean isGeofencingSupported() {
+ return mIsGeofencingSupported;
+ }
+
+ @Override
+ protected boolean addGeofence(int geofenceId, double latitude, double longitude, double radius,
+ int lastTransition, int monitorTransitions, int notificationResponsiveness,
+ int unknownTimer) {
+ if (mState.mGeofences.containsKey(geofenceId)) {
+ Objects.requireNonNull(mGnssNative).reportGeofenceAddStatus(geofenceId,
+ GEOFENCE_STATUS_ERROR_ID_EXISTS);
+ } else {
+ mState.mGeofences.put(geofenceId,
+ new GnssHalGeofence(geofenceId, latitude, longitude, radius, lastTransition,
+ monitorTransitions, notificationResponsiveness, unknownTimer, false));
+ Objects.requireNonNull(mGnssNative).reportGeofenceAddStatus(geofenceId,
+ GEOFENCE_STATUS_OPERATION_SUCCESS);
+ }
+ return true;
+ }
+
+ @Override
+ protected boolean resumeGeofence(int geofenceId, int monitorTransitions) {
+ GnssHalGeofence geofence = mState.mGeofences.get(geofenceId);
+ if (geofence != null) {
+ geofence.Paused = false;
+ geofence.MonitorTransitions = monitorTransitions;
+ Objects.requireNonNull(mGnssNative).reportGeofenceAddStatus(geofenceId,
+ GEOFENCE_STATUS_OPERATION_SUCCESS);
+ } else {
+ Objects.requireNonNull(mGnssNative).reportGeofenceAddStatus(geofenceId,
+ GEOFENCE_STATUS_ERROR_ID_UNKNOWN);
+ }
+ return true;
+ }
+
+ @Override
+ protected boolean pauseGeofence(int geofenceId) {
+ GnssHalGeofence geofence = mState.mGeofences.get(geofenceId);
+ if (geofence != null) {
+ geofence.Paused = true;
+ Objects.requireNonNull(mGnssNative).reportGeofenceAddStatus(geofenceId,
+ GEOFENCE_STATUS_OPERATION_SUCCESS);
+ } else {
+ Objects.requireNonNull(mGnssNative).reportGeofenceAddStatus(geofenceId,
+ GEOFENCE_STATUS_ERROR_ID_UNKNOWN);
+ }
+ return true;
+ }
+
+ @Override
+ protected boolean removeGeofence(int geofenceId) {
+ if (mState.mGeofences.remove(geofenceId) != null) {
+ Objects.requireNonNull(mGnssNative).reportGeofenceRemoveStatus(geofenceId,
+ GEOFENCE_STATUS_OPERATION_SUCCESS);
+ } else {
+ Objects.requireNonNull(mGnssNative).reportGeofenceRemoveStatus(geofenceId,
+ GEOFENCE_STATUS_ERROR_ID_UNKNOWN);
+ }
+ return true;
+ }
+
+ @Override
+ protected boolean isGnssVisibilityControlSupported() {
+ return mIsVisibilityControlSupported;
+ }
+
+ @Override
+ protected void sendNiResponse(int notificationId, int userResponse) {}
+
+ @Override
+ protected void requestPowerStats() {
+ Objects.requireNonNull(mGnssNative).reportGnssPowerStats(mState.mPowerStats);
+ }
+
+ @Override
+ protected void setAgpsServer(int type, String hostname, int port) {}
+
+ @Override
+ protected void setAgpsSetId(int type, String setId) {}
+
+ @Override
+ protected void setAgpsReferenceLocationCellId(int type, int mcc, int mnc, int lac, int cid) {}
+
+ @Override
+ protected boolean isPsdsSupported() {
+ return true;
+ }
+
+ @Override
+ protected void injectPsdsData(byte[] data, int length, int psdsType) {}
+}
diff --git a/services/tests/mockingservicestests/src/com/android/server/location/injector/FakeEmergencyHelper.java b/services/tests/mockingservicestests/src/com/android/server/location/injector/FakeEmergencyHelper.java
new file mode 100644
index 0000000..2cf57da
--- /dev/null
+++ b/services/tests/mockingservicestests/src/com/android/server/location/injector/FakeEmergencyHelper.java
@@ -0,0 +1,36 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.location.injector;
+
+/**
+ * Version of EmergencyHelper for testing.
+ */
+public class FakeEmergencyHelper extends EmergencyHelper {
+
+ private boolean mInEmergency;
+
+ public FakeEmergencyHelper() {}
+
+ public void setInEmergency(boolean inEmergency) {
+ mInEmergency = inEmergency;
+ }
+
+ @Override
+ public boolean isInEmergency(long extensionTimeMs) {
+ return mInEmergency;
+ }
+}
diff --git a/services/tests/mockingservicestests/src/com/android/server/location/injector/TestInjector.java b/services/tests/mockingservicestests/src/com/android/server/location/injector/TestInjector.java
index f3c31c2..8e5b16e 100644
--- a/services/tests/mockingservicestests/src/com/android/server/location/injector/TestInjector.java
+++ b/services/tests/mockingservicestests/src/com/android/server/location/injector/TestInjector.java
@@ -28,6 +28,7 @@
private final FakeLocationPowerSaveModeHelper mLocationPowerSaveModeHelper;
private final FakeScreenInteractiveHelper mScreenInteractiveHelper;
private final LocationAttributionHelper mLocationAttributionHelper;
+ private final FakeEmergencyHelper mEmergencyHelper;
private final LocationUsageLogger mLocationUsageLogger;
public TestInjector() {
@@ -41,6 +42,7 @@
mLocationPowerSaveModeHelper = new FakeLocationPowerSaveModeHelper(mLocationEventLog);
mScreenInteractiveHelper = new FakeScreenInteractiveHelper();
mLocationAttributionHelper = new LocationAttributionHelper(mAppOpsHelper);
+ mEmergencyHelper = new FakeEmergencyHelper();
mLocationUsageLogger = new LocationUsageLogger();
}
@@ -90,6 +92,11 @@
}
@Override
+ public EmergencyHelper getEmergencyHelper() {
+ return mEmergencyHelper;
+ }
+
+ @Override
public LocationUsageLogger getLocationUsageLogger() {
return mLocationUsageLogger;
}
diff --git a/services/tests/mockingservicestests/src/com/android/server/location/provider/LocationProviderManagerTest.java b/services/tests/mockingservicestests/src/com/android/server/location/provider/LocationProviderManagerTest.java
index 63b36fc..df7a445 100644
--- a/services/tests/mockingservicestests/src/com/android/server/location/provider/LocationProviderManagerTest.java
+++ b/services/tests/mockingservicestests/src/com/android/server/location/provider/LocationProviderManagerTest.java
@@ -66,6 +66,7 @@
import android.location.LocationManagerInternal.ProviderEnabledListener;
import android.location.LocationRequest;
import android.location.LocationResult;
+import android.location.ProviderProperties;
import android.location.util.identity.CallerIdentity;
import android.os.Bundle;
import android.os.ICancellationSignal;
@@ -80,7 +81,6 @@
import androidx.test.filters.SmallTest;
import androidx.test.runner.AndroidJUnit4;
-import com.android.internal.location.ProviderProperties;
import com.android.internal.location.ProviderRequest;
import com.android.server.FgThread;
import com.android.server.LocalServices;
@@ -1016,8 +1016,7 @@
private final ArrayList<Runnable> mFlushCallbacks = new ArrayList<>();
TestProvider(ProviderProperties properties, CallerIdentity identity) {
- super(DIRECT_EXECUTOR, identity);
- setProperties(properties);
+ super(DIRECT_EXECUTOR, identity, properties);
}
public void setProviderAllowed(boolean allowed) {
diff --git a/services/tests/mockingservicestests/src/com/android/server/location/provider/MockableLocationProviderTest.java b/services/tests/mockingservicestests/src/com/android/server/location/provider/MockableLocationProviderTest.java
index bcf65d3..daa8a22 100644
--- a/services/tests/mockingservicestests/src/com/android/server/location/provider/MockableLocationProviderTest.java
+++ b/services/tests/mockingservicestests/src/com/android/server/location/provider/MockableLocationProviderTest.java
@@ -15,8 +15,6 @@
*/
package com.android.server.location.provider;
-import static androidx.test.ext.truth.location.LocationSubject.assertThat;
-
import static com.android.internal.location.ProviderRequest.EMPTY_REQUEST;
import static com.google.common.truth.Truth.assertThat;
@@ -29,13 +27,13 @@
import android.location.Criteria;
import android.location.Location;
import android.location.LocationResult;
+import android.location.ProviderProperties;
import android.location.util.identity.CallerIdentity;
import android.platform.test.annotations.Presubmit;
import androidx.test.filters.SmallTest;
import androidx.test.runner.AndroidJUnit4;
-import com.android.internal.location.ProviderProperties;
import com.android.internal.location.ProviderRequest;
import com.android.server.location.test.FakeProvider;
import com.android.server.location.test.ProviderListenerCapture;
diff --git a/services/tests/mockingservicestests/src/com/android/server/location/test/FakeProvider.java b/services/tests/mockingservicestests/src/com/android/server/location/test/FakeProvider.java
index 9266d6f..1eb0386 100644
--- a/services/tests/mockingservicestests/src/com/android/server/location/test/FakeProvider.java
+++ b/services/tests/mockingservicestests/src/com/android/server/location/test/FakeProvider.java
@@ -40,7 +40,7 @@
private final FakeProviderInterface mFakeInterface;
public FakeProvider(FakeProviderInterface fakeInterface) {
- super(Runnable::run);
+ super(Runnable::run, null, null);
mFakeInterface = fakeInterface;
}
diff --git a/services/tests/servicestests/src/com/android/internal/location/timezone/LocationTimeZoneEventTest.java b/services/tests/servicestests/src/com/android/internal/location/timezone/LocationTimeZoneEventTest.java
deleted file mode 100644
index 84b886e..0000000
--- a/services/tests/servicestests/src/com/android/internal/location/timezone/LocationTimeZoneEventTest.java
+++ /dev/null
@@ -1,138 +0,0 @@
-/*
- * Copyright 2020 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.internal.location.timezone;
-
-import static com.android.internal.location.timezone.ParcelableTestSupport.assertRoundTripParcelable;
-
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertNotEquals;
-
-import static java.util.Collections.singletonList;
-
-import org.junit.Test;
-
-import java.util.List;
-
-public class LocationTimeZoneEventTest {
-
- private static final long ARBITRARY_ELAPSED_REALTIME_MILLIS = 9999;
-
- private static final List<String> ARBITRARY_TIME_ZONE_IDS = singletonList("Europe/London");
-
- @Test(expected = RuntimeException.class)
- public void testSetInvalidEventType() {
- new LocationTimeZoneEvent.Builder().setEventType(Integer.MAX_VALUE);
- }
-
- @Test(expected = RuntimeException.class)
- public void testBuildUnsetEventType() {
- new LocationTimeZoneEvent.Builder()
- .setTimeZoneIds(ARBITRARY_TIME_ZONE_IDS)
- .setElapsedRealtimeMillis(ARBITRARY_ELAPSED_REALTIME_MILLIS)
- .build();
- }
-
- @Test(expected = RuntimeException.class)
- public void testInvalidTimeZoneIds() {
- new LocationTimeZoneEvent.Builder()
- .setEventType(LocationTimeZoneEvent.EVENT_TYPE_UNCERTAIN)
- .setTimeZoneIds(ARBITRARY_TIME_ZONE_IDS)
- .setElapsedRealtimeMillis(ARBITRARY_ELAPSED_REALTIME_MILLIS)
- .build();
- }
-
- @Test
- public void testEquals() {
- LocationTimeZoneEvent.Builder builder1 = new LocationTimeZoneEvent.Builder()
- .setEventType(LocationTimeZoneEvent.EVENT_TYPE_UNCERTAIN)
- .setElapsedRealtimeMillis(ARBITRARY_ELAPSED_REALTIME_MILLIS);
- {
- LocationTimeZoneEvent one = builder1.build();
- assertEquals(one, one);
- }
-
- LocationTimeZoneEvent.Builder builder2 = new LocationTimeZoneEvent.Builder()
- .setEventType(LocationTimeZoneEvent.EVENT_TYPE_UNCERTAIN)
- .setElapsedRealtimeMillis(ARBITRARY_ELAPSED_REALTIME_MILLIS);
- {
- LocationTimeZoneEvent one = builder1.build();
- LocationTimeZoneEvent two = builder2.build();
- assertEquals(one, two);
- assertEquals(two, one);
- }
-
- builder1.setElapsedRealtimeMillis(ARBITRARY_ELAPSED_REALTIME_MILLIS + 1);
- {
- LocationTimeZoneEvent one = builder1.build();
- LocationTimeZoneEvent two = builder2.build();
- assertNotEquals(one, two);
- assertNotEquals(two, one);
- }
-
- builder2.setElapsedRealtimeMillis(ARBITRARY_ELAPSED_REALTIME_MILLIS + 1);
- {
- LocationTimeZoneEvent one = builder1.build();
- LocationTimeZoneEvent two = builder2.build();
- assertEquals(one, two);
- assertEquals(two, one);
- }
-
- builder2.setEventType(LocationTimeZoneEvent.EVENT_TYPE_SUCCESS);
- {
- LocationTimeZoneEvent one = builder1.build();
- LocationTimeZoneEvent two = builder2.build();
- assertNotEquals(one, two);
- assertNotEquals(two, one);
- }
-
- builder1.setEventType(LocationTimeZoneEvent.EVENT_TYPE_SUCCESS);
- {
- LocationTimeZoneEvent one = builder1.build();
- LocationTimeZoneEvent two = builder2.build();
- assertEquals(one, two);
- assertEquals(two, one);
- }
-
- builder2.setTimeZoneIds(ARBITRARY_TIME_ZONE_IDS);
- {
- LocationTimeZoneEvent one = builder1.build();
- LocationTimeZoneEvent two = builder2.build();
- assertNotEquals(one, two);
- assertNotEquals(two, one);
- }
-
- builder1.setTimeZoneIds(ARBITRARY_TIME_ZONE_IDS);
- {
- LocationTimeZoneEvent one = builder1.build();
- LocationTimeZoneEvent two = builder2.build();
- assertEquals(one, two);
- assertEquals(two, one);
- }
- }
-
- @Test
- public void testParcelable() {
- LocationTimeZoneEvent.Builder builder = new LocationTimeZoneEvent.Builder()
- .setEventType(LocationTimeZoneEvent.EVENT_TYPE_PERMANENT_FAILURE)
- .setElapsedRealtimeMillis(ARBITRARY_ELAPSED_REALTIME_MILLIS);
- assertRoundTripParcelable(builder.build());
-
- builder.setEventType(LocationTimeZoneEvent.EVENT_TYPE_SUCCESS)
- .setTimeZoneIds(ARBITRARY_TIME_ZONE_IDS);
- assertRoundTripParcelable(builder.build());
- }
-}
diff --git a/services/tests/servicestests/src/com/android/internal/location/timezone/LocationTimeZoneProviderRequestTest.java b/services/tests/servicestests/src/com/android/internal/location/timezone/LocationTimeZoneProviderRequestTest.java
deleted file mode 100644
index 95daa36..0000000
--- a/services/tests/servicestests/src/com/android/internal/location/timezone/LocationTimeZoneProviderRequestTest.java
+++ /dev/null
@@ -1,39 +0,0 @@
-/*
- * Copyright 2020 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.internal.location.timezone;
-
-import static com.android.internal.location.timezone.ParcelableTestSupport.assertRoundTripParcelable;
-
-import org.junit.Test;
-
-import java.time.Duration;
-
-public class LocationTimeZoneProviderRequestTest {
-
- @Test
- public void testParcelable() {
- LocationTimeZoneProviderRequest.Builder builder =
- new LocationTimeZoneProviderRequest.Builder()
- .setReportLocationTimeZone(false);
- assertRoundTripParcelable(builder.build());
-
- builder.setReportLocationTimeZone(true)
- .setInitializationTimeoutMillis(Duration.ofMinutes(5).toMillis());
-
- assertRoundTripParcelable(builder.build());
- }
-}
diff --git a/services/tests/servicestests/src/com/android/internal/location/timezone/ParcelableTestSupport.java b/services/tests/servicestests/src/com/android/internal/location/timezone/ParcelableTestSupport.java
deleted file mode 100644
index ece5d00..0000000
--- a/services/tests/servicestests/src/com/android/internal/location/timezone/ParcelableTestSupport.java
+++ /dev/null
@@ -1,53 +0,0 @@
-/*
- * Copyright 2019 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.internal.location.timezone;
-
-import static org.junit.Assert.assertEquals;
-
-import android.os.Parcel;
-import android.os.Parcelable;
-
-import java.lang.reflect.Field;
-
-/** Utility methods related to {@link Parcelable} objects used in several tests. */
-final class ParcelableTestSupport {
-
- private ParcelableTestSupport() {}
-
- /** Returns the result of parceling and unparceling the argument. */
- @SuppressWarnings("unchecked")
- public static <T extends Parcelable> T roundTripParcelable(T parcelable) {
- Parcel parcel = Parcel.obtain();
- parcel.writeTypedObject(parcelable, 0);
- parcel.setDataPosition(0);
-
- Parcelable.Creator<T> creator;
- try {
- Field creatorField = parcelable.getClass().getField("CREATOR");
- creator = (Parcelable.Creator<T>) creatorField.get(null);
- } catch (NoSuchFieldException | IllegalAccessException e) {
- throw new AssertionError(e);
- }
- T toReturn = parcel.readTypedObject(creator);
- parcel.recycle();
- return toReturn;
- }
-
- public static <T extends Parcelable> void assertRoundTripParcelable(T instance) {
- assertEquals(instance, roundTripParcelable(instance));
- }
-}
diff --git a/services/tests/servicestests/src/com/android/server/location/timezone/ControllerImplTest.java b/services/tests/servicestests/src/com/android/server/location/timezone/ControllerImplTest.java
index dc81237..4de4d95 100644
--- a/services/tests/servicestests/src/com/android/server/location/timezone/ControllerImplTest.java
+++ b/services/tests/servicestests/src/com/android/server/location/timezone/ControllerImplTest.java
@@ -1053,11 +1053,6 @@
}
@Override
- void logWarn(String msg) {
- System.out.println(msg);
- }
-
- @Override
public void dump(IndentingPrintWriter pw, String[] args) {
// Nothing needed for tests.
}
diff --git a/services/tests/servicestests/src/com/android/server/location/timezone/OWNERS b/services/tests/servicestests/src/com/android/server/location/timezone/OWNERS
new file mode 100644
index 0000000..28aff18
--- /dev/null
+++ b/services/tests/servicestests/src/com/android/server/location/timezone/OWNERS
@@ -0,0 +1,3 @@
+# Bug component: 847766
+nfuller@google.com
+include /core/java/android/app/timedetector/OWNERS
diff --git a/services/tests/uiservicestests/src/com/android/server/notification/NotificationListenersTest.java b/services/tests/uiservicestests/src/com/android/server/notification/NotificationListenersTest.java
new file mode 100644
index 0000000..a093e0d
--- /dev/null
+++ b/services/tests/uiservicestests/src/com/android/server/notification/NotificationListenersTest.java
@@ -0,0 +1,242 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.server.notification;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.anyInt;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.spy;
+import static org.mockito.Mockito.when;
+
+import android.app.INotificationManager;
+import android.content.ComponentName;
+import android.content.pm.IPackageManager;
+import android.content.pm.PackageManager;
+import android.content.pm.ResolveInfo;
+import android.content.pm.ServiceInfo;
+import android.service.notification.NotificationListenerFilter;
+import android.util.ArraySet;
+import android.util.Pair;
+import android.util.TypedXmlPullParser;
+import android.util.TypedXmlSerializer;
+import android.util.Xml;
+
+import com.android.server.UiServiceTestCase;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+
+import java.io.BufferedInputStream;
+import java.io.BufferedOutputStream;
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.util.ArrayList;
+import java.util.List;
+
+public class NotificationListenersTest extends UiServiceTestCase {
+
+ @Mock
+ private PackageManager mPm;
+ @Mock
+ private IPackageManager miPm;
+
+ @Mock
+ NotificationManagerService mNm;
+ @Mock
+ private INotificationManager mINm;
+
+ NotificationManagerService.NotificationListeners mListeners;
+
+ private ComponentName mCn1 = new ComponentName("pkg", "pkg.cmp");
+ private ComponentName mCn2 = new ComponentName("pkg2", "pkg2.cmp2");
+
+
+ @Before
+ public void setUp() throws Exception {
+ MockitoAnnotations.initMocks(this);
+ getContext().setMockPackageManager(mPm);
+
+ mListeners = spy(mNm.new NotificationListeners(
+ mContext, new Object(), mock(ManagedServices.UserProfiles.class), miPm));
+ when(mNm.getBinderService()).thenReturn(mINm);
+ }
+
+ @Test
+ public void testReadExtraTag() throws Exception {
+ String xml = "<requested_listeners>"
+ + "<listener component=\"" + mCn1.flattenToString() + "\" user=\"0\">"
+ + "<allowed types=\"7\" />"
+ + "<disallowed pkgs=\"\" />"
+ + "</listener>"
+ + "<listener component=\"" + mCn2.flattenToString() + "\" user=\"10\">"
+ + "<allowed types=\"4\" />"
+ + "<disallowed pkgs=\"something\" />"
+ + "</listener>"
+ + "</requested_listeners>";
+
+ TypedXmlPullParser parser = Xml.newFastPullParser();
+ parser.setInput(new BufferedInputStream(
+ new ByteArrayInputStream(xml.getBytes())), null);
+ parser.nextTag();
+ mListeners.readExtraTag("requested_listeners", parser);
+
+ validateListenersFromXml();
+ }
+
+ @Test
+ public void testWriteExtraTag() throws Exception {
+ NotificationListenerFilter nlf = new NotificationListenerFilter(7, new ArraySet<>());
+ NotificationListenerFilter nlf2 =
+ new NotificationListenerFilter(4, new ArraySet<>(new String[] {"something"}));
+ mListeners.setNotificationListenerFilter(Pair.create(mCn1, 0), nlf);
+ mListeners.setNotificationListenerFilter(Pair.create(mCn2, 10), nlf2);
+
+ TypedXmlSerializer serializer = Xml.newFastSerializer();
+ ByteArrayOutputStream baos = new ByteArrayOutputStream();
+ serializer.setOutput(new BufferedOutputStream(baos), "utf-8");
+ serializer.startDocument(null, true);
+ mListeners.writeExtraXmlTags(serializer);
+ serializer.endDocument();
+ serializer.flush();
+
+ TypedXmlPullParser parser = Xml.newFastPullParser();
+ parser.setInput(new BufferedInputStream(
+ new ByteArrayInputStream(baos.toByteArray())), null);
+ parser.nextTag();
+ mListeners.readExtraTag("requested_listeners", parser);
+
+ validateListenersFromXml();
+ }
+
+ private void validateListenersFromXml() {
+ assertThat(mListeners.getNotificationListenerFilter(Pair.create(mCn1, 0)).getTypes())
+ .isEqualTo(7);
+ assertThat(mListeners.getNotificationListenerFilter(Pair.create(mCn1, 0))
+ .getDisallowedPackages())
+ .isEmpty();
+
+ assertThat(mListeners.getNotificationListenerFilter(Pair.create(mCn2, 10)).getTypes())
+ .isEqualTo(4);
+ assertThat(mListeners.getNotificationListenerFilter(Pair.create(mCn2, 10))
+ .getDisallowedPackages())
+ .contains("something");
+ }
+
+ @Test
+ public void testOnUserRemoved() {
+ NotificationListenerFilter nlf = new NotificationListenerFilter(7, new ArraySet<>());
+ NotificationListenerFilter nlf2 =
+ new NotificationListenerFilter(4, new ArraySet<>(new String[] {"something"}));
+ mListeners.setNotificationListenerFilter(Pair.create(mCn1, 0), nlf);
+ mListeners.setNotificationListenerFilter(Pair.create(mCn2, 10), nlf2);
+
+ mListeners.onUserRemoved(0);
+
+ assertThat(mListeners.getNotificationListenerFilter(Pair.create(mCn1, 0))).isNull();
+ assertThat(mListeners.getNotificationListenerFilter(Pair.create(mCn2, 10)).getTypes())
+ .isEqualTo(4);
+ }
+
+ @Test
+ public void testOnUserUnlocked() {
+ // one exists already, say from xml
+ NotificationListenerFilter nlf =
+ new NotificationListenerFilter(4, new ArraySet<>(new String[] {"something"}));
+ mListeners.setNotificationListenerFilter(Pair.create(mCn2, 0), nlf);
+
+ // new service exists or backfilling on upgrade to S
+ ServiceInfo si = new ServiceInfo();
+ si.permission = mListeners.getConfig().bindPermission;
+ si.packageName = "new";
+ si.name = "comp";
+ ResolveInfo ri = new ResolveInfo();
+ ri.serviceInfo = si;
+
+ // incorrect service
+ ServiceInfo si2 = new ServiceInfo();
+ ResolveInfo ri2 = new ResolveInfo();
+ ri2.serviceInfo = si2;
+ si2.packageName = "new2";
+ si2.name = "comp2";
+
+ List<ResolveInfo> ris = new ArrayList<>();
+ ris.add(ri);
+ ris.add(ri2);
+
+ when(mPm.queryIntentServicesAsUser(any(), anyInt(), anyInt())).thenReturn(ris);
+
+ mListeners.onUserUnlocked(0);
+
+ assertThat(mListeners.getNotificationListenerFilter(Pair.create(mCn2, 0)).getTypes())
+ .isEqualTo(4);
+ assertThat(mListeners.getNotificationListenerFilter(Pair.create(mCn2, 0))
+ .getDisallowedPackages())
+ .contains("something");
+
+ assertThat(mListeners.getNotificationListenerFilter(
+ Pair.create(si.getComponentName(), 0)).getTypes())
+ .isEqualTo(7);
+ assertThat(mListeners.getNotificationListenerFilter(Pair.create(si.getComponentName(), 0))
+ .getDisallowedPackages())
+ .isEmpty();
+
+ assertThat(mListeners.getNotificationListenerFilter(Pair.create(si2.getComponentName(), 0)))
+ .isNull();
+
+ }
+
+ @Test
+ public void testOnPackageChanged() {
+ NotificationListenerFilter nlf = new NotificationListenerFilter(7, new ArraySet<>());
+ NotificationListenerFilter nlf2 =
+ new NotificationListenerFilter(4, new ArraySet<>(new String[] {"something"}));
+ mListeners.setNotificationListenerFilter(Pair.create(mCn1, 0), nlf);
+ mListeners.setNotificationListenerFilter(Pair.create(mCn2, 10), nlf2);
+
+ String[] pkgs = new String[] {mCn1.getPackageName()};
+ int[] uids = new int[] {1};
+ mListeners.onPackagesChanged(false, pkgs, uids);
+
+ // not removing; no change
+ assertThat(mListeners.getNotificationListenerFilter(Pair.create(mCn1, 0)).getTypes())
+ .isEqualTo(7);
+ assertThat(mListeners.getNotificationListenerFilter(Pair.create(mCn2, 10)).getTypes())
+ .isEqualTo(4);
+ }
+
+ @Test
+ public void testOnPackageChanged_removing() {
+ NotificationListenerFilter nlf = new NotificationListenerFilter(7, new ArraySet<>());
+ NotificationListenerFilter nlf2 =
+ new NotificationListenerFilter(4, new ArraySet<>(new String[] {"something"}));
+ mListeners.setNotificationListenerFilter(Pair.create(mCn1, 0), nlf);
+ mListeners.setNotificationListenerFilter(Pair.create(mCn2, 0), nlf2);
+
+ String[] pkgs = new String[] {mCn1.getPackageName()};
+ int[] uids = new int[] {1};
+ mListeners.onPackagesChanged(true, pkgs, uids);
+
+ // only mCn1 removed
+ assertThat(mListeners.getNotificationListenerFilter(Pair.create(mCn1, 0))).isNull();
+ assertThat(mListeners.getNotificationListenerFilter(Pair.create(mCn2, 0)).getTypes())
+ .isEqualTo(4);
+ }
+
+}
diff --git a/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java b/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java
index a18bce7..bd622e1 100755
--- a/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java
+++ b/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java
@@ -55,6 +55,7 @@
import static android.os.UserHandle.USER_SYSTEM;
import static android.service.notification.Adjustment.KEY_IMPORTANCE;
import static android.service.notification.Adjustment.KEY_USER_SENTIMENT;
+import static android.service.notification.NotificationListenerService.FLAG_FILTER_TYPE_ALERTING;
import static android.service.notification.NotificationListenerService.Ranking.USER_SENTIMENT_NEGATIVE;
import static android.service.notification.NotificationListenerService.Ranking.USER_SENTIMENT_NEUTRAL;
@@ -143,6 +144,7 @@
import android.provider.Settings;
import android.service.notification.Adjustment;
import android.service.notification.ConversationChannelWrapper;
+import android.service.notification.NotificationListenerFilter;
import android.service.notification.NotificationListenerService;
import android.service.notification.NotificationStats;
import android.service.notification.StatusBarNotification;
@@ -269,6 +271,8 @@
@Mock
private NotificationListeners mListeners;
+ @Mock
+ private NotificationListenerFilter mNlf;
@Mock private NotificationAssistants mAssistants;
@Mock private ConditionProviders mConditionProviders;
private ManagedServices.ManagedServiceInfo mListener;
@@ -459,6 +463,10 @@
mPolicyFile.finishWrite(fos);
// Setup managed services
+ when(mNlf.isTypeAllowed(anyInt())).thenReturn(true);
+ when(mNlf.isPackageAllowed(anyString())).thenReturn(true);
+ when(mNlf.isPackageAllowed(null)).thenReturn(true);
+ when(mListeners.getNotificationListenerFilter(any())).thenReturn(mNlf);
mListener = mListeners.new ManagedServiceInfo(
null, new ComponentName(PKG, "test_class"),
UserHandle.getUserId(mUid), true, null, 0);
@@ -3596,7 +3604,7 @@
mService.mNotificationDelegate.onNotificationDirectReplied(r.getKey());
assertTrue(mService.getNotificationRecord(r.getKey()).getStats().hasDirectReplied());
- verify(mAssistants).notifyAssistantNotificationDirectReplyLocked(eq(r.getSbn()));
+ verify(mAssistants).notifyAssistantNotificationDirectReplyLocked(eq(r));
assertEquals(1, mNotificationRecordLogger.numCalls());
assertEquals(NotificationRecordLogger.NotificationEvent.NOTIFICATION_DIRECT_REPLIED,
@@ -3610,14 +3618,14 @@
mService.mNotificationDelegate.onNotificationExpansionChanged(r.getKey(), true, true,
NOTIFICATION_LOCATION_UNKNOWN);
- verify(mAssistants).notifyAssistantExpansionChangedLocked(eq(r.getSbn()), eq(true),
- eq((true)));
+ verify(mAssistants).notifyAssistantExpansionChangedLocked(eq(r.getSbn()),
+ eq(FLAG_FILTER_TYPE_ALERTING), eq(true), eq((true)));
assertTrue(mService.getNotificationRecord(r.getKey()).getStats().hasExpanded());
mService.mNotificationDelegate.onNotificationExpansionChanged(r.getKey(), true, false,
NOTIFICATION_LOCATION_UNKNOWN);
- verify(mAssistants).notifyAssistantExpansionChangedLocked(eq(r.getSbn()), eq(true),
- eq((false)));
+ verify(mAssistants).notifyAssistantExpansionChangedLocked(eq(r.getSbn()),
+ eq(FLAG_FILTER_TYPE_ALERTING), eq(true), eq((false)));
assertTrue(mService.getNotificationRecord(r.getKey()).getStats().hasExpanded());
assertEquals(2, mNotificationRecordLogger.numCalls());
@@ -3635,14 +3643,14 @@
mService.mNotificationDelegate.onNotificationExpansionChanged(r.getKey(), false, true,
NOTIFICATION_LOCATION_UNKNOWN);
assertFalse(mService.getNotificationRecord(r.getKey()).getStats().hasExpanded());
- verify(mAssistants).notifyAssistantExpansionChangedLocked(eq(r.getSbn()), eq(false),
- eq((true)));
+ verify(mAssistants).notifyAssistantExpansionChangedLocked(eq(r.getSbn()),
+ eq(FLAG_FILTER_TYPE_ALERTING), eq(false), eq((true)));
mService.mNotificationDelegate.onNotificationExpansionChanged(r.getKey(), false, false,
NOTIFICATION_LOCATION_UNKNOWN);
assertFalse(mService.getNotificationRecord(r.getKey()).getStats().hasExpanded());
verify(mAssistants).notifyAssistantExpansionChangedLocked(
- eq(r.getSbn()), eq(false), eq((false)));
+ eq(r.getSbn()), eq(FLAG_FILTER_TYPE_ALERTING), eq(false), eq((false)));
}
@Test
@@ -3662,11 +3670,11 @@
final NotificationVisibility nv = NotificationVisibility.obtain(r.getKey(), 1, 2, true);
mService.mNotificationDelegate.onNotificationVisibilityChanged(
new NotificationVisibility[] {nv}, new NotificationVisibility[]{});
- verify(mAssistants).notifyAssistantVisibilityChangedLocked(eq(r.getSbn()), eq(true));
+ verify(mAssistants).notifyAssistantVisibilityChangedLocked(eq(r), eq(true));
assertTrue(mService.getNotificationRecord(r.getKey()).getStats().hasSeen());
mService.mNotificationDelegate.onNotificationVisibilityChanged(
new NotificationVisibility[] {}, new NotificationVisibility[]{nv});
- verify(mAssistants).notifyAssistantVisibilityChangedLocked(eq(r.getSbn()), eq(false));
+ verify(mAssistants).notifyAssistantVisibilityChangedLocked(eq(r), eq(false));
assertTrue(mService.getNotificationRecord(r.getKey()).getStats().hasSeen());
}
@@ -5324,7 +5332,7 @@
r.getKey(), replyIndex, reply, NOTIFICATION_LOCATION_UNKNOWN,
modifiedBeforeSending);
verify(mAssistants).notifyAssistantSuggestedReplySent(
- eq(r.getSbn()), eq(reply), eq(generatedByAssistant));
+ eq(r.getSbn()), eq(FLAG_FILTER_TYPE_ALERTING), eq(reply), eq(generatedByAssistant));
assertEquals(1, mNotificationRecordLogger.numCalls());
assertEquals(NotificationRecordLogger.NotificationEvent.NOTIFICATION_SMART_REPLIED,
mNotificationRecordLogger.event(0));
@@ -5346,7 +5354,7 @@
10, 10, r.getKey(), actionIndex, action, notificationVisibility,
generatedByAssistant);
verify(mAssistants).notifyAssistantActionClicked(
- eq(r.getSbn()), eq(action), eq(generatedByAssistant));
+ eq(r), eq(action), eq(generatedByAssistant));
assertEquals(1, mNotificationRecordLogger.numCalls());
assertEquals(
@@ -5370,7 +5378,7 @@
10, 10, r.getKey(), actionIndex, action, notificationVisibility,
generatedByAssistant);
verify(mAssistants).notifyAssistantActionClicked(
- eq(r.getSbn()), eq(action), eq(generatedByAssistant));
+ eq(r), eq(action), eq(generatedByAssistant));
assertEquals(1, mNotificationRecordLogger.numCalls());
assertEquals(
@@ -7249,7 +7257,7 @@
when(info.enabledAndUserMatches(info.userid)).thenReturn(false);
when(mAssistants.checkServiceTokenLocked(any())).thenReturn(assistant);
- assertFalse(mService.isVisibleToListener(sbn, info));
+ assertFalse(mService.isVisibleToListener(sbn, 0, info));
}
@Test
@@ -7262,7 +7270,7 @@
when(info.enabledAndUserMatches(info.userid)).thenReturn(true);
when(mAssistants.checkServiceTokenLocked(any())).thenReturn(null);
- assertTrue(mService.isVisibleToListener(sbn, info));
+ assertTrue(mService.isVisibleToListener(sbn, 0, info));
}
@Test
@@ -7277,7 +7285,7 @@
when(info.enabledAndUserMatches(info.userid)).thenReturn(true);
when(mAssistants.checkServiceTokenLocked(any())).thenReturn(assistant);
- assertFalse(mService.isVisibleToListener(sbn, info));
+ assertFalse(mService.isVisibleToListener(sbn, 0, info));
}
@Test
@@ -7292,7 +7300,42 @@
when(info.enabledAndUserMatches(info.userid)).thenReturn(true);
when(mAssistants.checkServiceTokenLocked(any())).thenReturn(assistant);
- assertTrue(mService.isVisibleToListener(sbn, info));
+ assertTrue(mService.isVisibleToListener(sbn, 0, info));
+ }
+
+ @Test
+ public void testIsVisibleToListener_mismatchedType() {
+ when(mNlf.isTypeAllowed(anyInt())).thenReturn(false);
+
+ StatusBarNotification sbn = mock(StatusBarNotification.class);
+ when(sbn.getUserId()).thenReturn(10);
+ ManagedServices.ManagedServiceInfo info = mock(ManagedServices.ManagedServiceInfo.class);
+ ManagedServices.ManagedServiceInfo assistant = mock(ManagedServices.ManagedServiceInfo.class);
+ info.userid = 10;
+ when(info.isSameUser(anyInt())).thenReturn(true);
+ when(assistant.isSameUser(anyInt())).thenReturn(true);
+ when(info.enabledAndUserMatches(info.userid)).thenReturn(true);
+ when(mAssistants.checkServiceTokenLocked(any())).thenReturn(assistant);
+
+ assertFalse(mService.isVisibleToListener(sbn, 0, info));
+ }
+
+ @Test
+ public void testIsVisibleToListener_disallowedPackage() {
+ when(mNlf.isPackageAllowed(null)).thenReturn(false);
+
+ StatusBarNotification sbn = mock(StatusBarNotification.class);
+ when(sbn.getUserId()).thenReturn(10);
+ ManagedServices.ManagedServiceInfo info = mock(ManagedServices.ManagedServiceInfo.class);
+ ManagedServices.ManagedServiceInfo assistant =
+ mock(ManagedServices.ManagedServiceInfo.class);
+ info.userid = 10;
+ when(info.isSameUser(anyInt())).thenReturn(true);
+ when(assistant.isSameUser(anyInt())).thenReturn(true);
+ when(info.enabledAndUserMatches(info.userid)).thenReturn(true);
+ when(mAssistants.checkServiceTokenLocked(any())).thenReturn(assistant);
+
+ assertFalse(mService.isVisibleToListener(sbn, 0, info));
}
@Test
diff --git a/services/tests/uiservicestests/src/com/android/server/notification/NotificationRecordTest.java b/services/tests/uiservicestests/src/com/android/server/notification/NotificationRecordTest.java
index 976f408..da613e6 100644
--- a/services/tests/uiservicestests/src/com/android/server/notification/NotificationRecordTest.java
+++ b/services/tests/uiservicestests/src/com/android/server/notification/NotificationRecordTest.java
@@ -21,6 +21,9 @@
import static android.app.NotificationManager.IMPORTANCE_LOW;
import static android.service.notification.Adjustment.KEY_IMPORTANCE;
import static android.service.notification.Adjustment.KEY_NOT_CONVERSATION;
+import static android.service.notification.NotificationListenerService.FLAG_FILTER_TYPE_ALERTING;
+import static android.service.notification.NotificationListenerService.FLAG_FILTER_TYPE_CONVERSATIONS;
+import static android.service.notification.NotificationListenerService.FLAG_FILTER_TYPE_SILENT;
import static android.service.notification.NotificationListenerService.Ranking.USER_SENTIMENT_NEGATIVE;
import static android.service.notification.NotificationListenerService.Ranking.USER_SENTIMENT_NEUTRAL;
import static android.service.notification.NotificationListenerService.Ranking.USER_SENTIMENT_POSITIVE;
@@ -910,11 +913,13 @@
record.setAssistantImportance(IMPORTANCE_LOW);
record.calculateImportance();
assertEquals(IMPORTANCE_LOW, record.getImportance());
+ assertEquals(FLAG_FILTER_TYPE_SILENT, record.getNotificationType());
record.updateNotificationChannel(
new NotificationChannel(channelId, "", IMPORTANCE_DEFAULT));
assertEquals(IMPORTANCE_LOW, record.getImportance());
+ assertEquals(FLAG_FILTER_TYPE_SILENT, record.getNotificationType());
}
@Test
@@ -1125,6 +1130,7 @@
record.setShortcutInfo(mock(ShortcutInfo.class));
assertTrue(record.isConversation());
+ assertEquals(FLAG_FILTER_TYPE_CONVERSATIONS, record.getNotificationType());
}
@Test
@@ -1134,6 +1140,7 @@
record.setShortcutInfo(null);
assertTrue(record.isConversation());
+ assertEquals(FLAG_FILTER_TYPE_CONVERSATIONS, record.getNotificationType());
}
@Test
@@ -1144,6 +1151,7 @@
record.setHasSentValidMsg(true);
assertFalse(record.isConversation());
+ assertEquals(FLAG_FILTER_TYPE_ALERTING, record.getNotificationType());
}
@Test
diff --git a/services/tests/uiservicestests/src/com/android/server/notification/ZenModeHelperTest.java b/services/tests/uiservicestests/src/com/android/server/notification/ZenModeHelperTest.java
index cfdd246..57d5323 100644
--- a/services/tests/uiservicestests/src/com/android/server/notification/ZenModeHelperTest.java
+++ b/services/tests/uiservicestests/src/com/android/server/notification/ZenModeHelperTest.java
@@ -58,6 +58,7 @@
import static org.mockito.Mockito.doNothing;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.reset;
import static org.mockito.Mockito.spy;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
@@ -101,7 +102,6 @@
import com.android.internal.R;
import com.android.internal.messages.nano.SystemMessageProto.SystemMessage;
-import com.android.internal.util.FastXmlSerializer;
import com.android.server.UiServiceTestCase;
import com.android.server.notification.ManagedServices.UserProfiles;
@@ -110,9 +110,7 @@
import org.junit.runner.RunWith;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
-import org.xmlpull.v1.XmlPullParser;
import org.xmlpull.v1.XmlPullParserException;
-import org.xmlpull.v1.XmlSerializer;
import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
@@ -134,9 +132,13 @@
private static final String EVENTS_DEFAULT_RULE_ID = "EVENTS_DEFAULT_RULE";
private static final String SCHEDULE_DEFAULT_RULE_ID = "EVERY_NIGHT_DEFAULT_RULE";
private static final int ZEN_MODE_FOR_TESTING = 99;
+ private static final String CUSTOM_PKG_NAME = "not.android";
+ private static final int CUSTOM_PKG_UID = 1;
+ private static final String CUSTOM_RULE_ID = "custom_rule";
ConditionProviders mConditionProviders;
@Mock NotificationManager mNotificationManager;
+ @Mock PackageManager mPackageManager;
private Resources mResources;
private TestableLooper mTestableLooper;
private ZenModeHelper mZenModeHelperSpy;
@@ -146,7 +148,7 @@
private WrappedSysUiStatsEvent.WrappedBuilderFactory mStatsEventBuilderFactory;
@Before
- public void setUp() {
+ public void setUp() throws PackageManager.NameNotFoundException {
MockitoAnnotations.initMocks(this);
mTestableLooper = TestableLooper.get(this);
@@ -169,6 +171,10 @@
mConditionProviders.addSystemProvider(new CountdownConditionProvider());
mZenModeHelperSpy = spy(new ZenModeHelper(mContext, mTestableLooper.getLooper(),
mConditionProviders, mStatsEventBuilderFactory));
+
+ when(mPackageManager.getPackageUidAsUser(eq(CUSTOM_PKG_NAME), anyInt()))
+ .thenReturn(CUSTOM_PKG_UID);
+ mZenModeHelperSpy.mPm = mPackageManager;
}
private XmlResourceParser getDefaultConfigParser() throws IOException, XmlPullParserException {
@@ -238,19 +244,24 @@
private ArrayMap<String, ZenModeConfig.ZenRule> getCustomAutomaticRules(int zenMode) {
ArrayMap<String, ZenModeConfig.ZenRule> automaticRules = new ArrayMap<>();
+ ZenModeConfig.ZenRule rule = createCustomAutomaticRule(zenMode, CUSTOM_RULE_ID);
+ automaticRules.put(rule.id, rule);
+ return automaticRules;
+ }
+
+ private ZenModeConfig.ZenRule createCustomAutomaticRule(int zenMode, String id) {
ZenModeConfig.ZenRule customRule = new ZenModeConfig.ZenRule();
final ScheduleInfo customRuleInfo = new ScheduleInfo();
customRule.enabled = true;
customRule.creationTime = 0;
- customRule.id = "customRule";
- customRule.name = "Custom Rule";
+ customRule.id = id;
+ customRule.name = "Custom Rule with id=" + id;
customRule.zenMode = zenMode;
customRule.conditionId = ZenModeConfig.toScheduleConditionId(customRuleInfo);
customRule.configurationActivity =
- new ComponentName("not.android", "ScheduleConditionProvider");
+ new ComponentName(CUSTOM_PKG_NAME, "ScheduleConditionProvider");
customRule.pkg = customRule.configurationActivity.getPackageName();
- automaticRules.put("customRule", customRule);
- return automaticRules;
+ return customRule;
}
@Test
@@ -893,7 +904,7 @@
if (builder.getAtomId() == DND_MODE_RULE) {
if (ZEN_MODE_FOR_TESTING == builder.getInt(ZEN_MODE_FIELD_NUMBER)) {
foundCustomEvent = true;
- assertEquals(0, builder.getInt(UID_FIELD_NUMBER));
+ assertEquals(CUSTOM_PKG_UID, builder.getInt(UID_FIELD_NUMBER));
assertTrue(builder.getBoolean(ENABLED_FIELD_NUMBER));
}
} else {
@@ -904,6 +915,46 @@
}
@Test
+ public void ruleUidsCached() throws Exception {
+ setupZenConfig();
+ // one enabled automatic rule
+ mZenModeHelperSpy.mConfig.automaticRules = getCustomAutomaticRules();
+ List<StatsEvent> events = new LinkedList<>();
+ // first time retrieving uid:
+ mZenModeHelperSpy.pullRules(events);
+ verify(mPackageManager, atLeastOnce()).getPackageUidAsUser(anyString(), anyInt());
+
+ // second time retrieving uid:
+ reset(mPackageManager);
+ mZenModeHelperSpy.pullRules(events);
+ verify(mPackageManager, never()).getPackageUidAsUser(anyString(), anyInt());
+
+ // new rule from same package + user added
+ reset(mPackageManager);
+ ZenModeConfig.ZenRule rule = createCustomAutomaticRule(ZEN_MODE_IMPORTANT_INTERRUPTIONS,
+ CUSTOM_RULE_ID + "2");
+ mZenModeHelperSpy.mConfig.automaticRules.put(rule.id, rule);
+ mZenModeHelperSpy.pullRules(events);
+ verify(mPackageManager, never()).getPackageUidAsUser(anyString(), anyInt());
+ }
+
+ @Test
+ public void ruleUidAutomaticZenRuleRemovedUpdatesCache() throws Exception {
+ when(mContext.checkCallingPermission(anyString()))
+ .thenReturn(PackageManager.PERMISSION_GRANTED);
+
+ setupZenConfig();
+ // one enabled automatic rule
+ mZenModeHelperSpy.mConfig.automaticRules = getCustomAutomaticRules();
+ List<StatsEvent> events = new LinkedList<>();
+
+ mZenModeHelperSpy.pullRules(events);
+ mZenModeHelperSpy.removeAutomaticZenRule(CUSTOM_RULE_ID, "test");
+ assertTrue(-1
+ == mZenModeHelperSpy.mRulesUidCache.getOrDefault(CUSTOM_PKG_NAME + "|" + 0, -1));
+ }
+
+ @Test
public void testProtoRedactsIds() throws Exception {
setupZenConfig();
// one enabled automatic rule
diff --git a/services/tests/wmtests/Android.bp b/services/tests/wmtests/Android.bp
index 1ecf850..cf977b4 100644
--- a/services/tests/wmtests/Android.bp
+++ b/services/tests/wmtests/Android.bp
@@ -47,6 +47,7 @@
"testables",
"ub-uiautomator",
"hamcrest-library",
+ "platform-compat-test-rules",
],
libs: [
diff --git a/services/tests/wmtests/src/com/android/server/wm/ActivityOptionsTest.java b/services/tests/wmtests/src/com/android/server/wm/ActivityOptionsTest.java
index 2acb647..8983b4e 100644
--- a/services/tests/wmtests/src/com/android/server/wm/ActivityOptionsTest.java
+++ b/services/tests/wmtests/src/com/android/server/wm/ActivityOptionsTest.java
@@ -16,7 +16,6 @@
package com.android.server.wm;
-import static android.app.ActivityTaskManager.SPLIT_SCREEN_CREATE_MODE_BOTTOM_OR_RIGHT;
import static android.app.WindowConfiguration.ACTIVITY_TYPE_STANDARD;
import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN;
import static android.view.WindowManager.LayoutParams.ROTATION_ANIMATION_ROTATE;
@@ -53,7 +52,6 @@
opts.setRotationAnimationHint(ROTATION_ANIMATION_ROTATE);
opts.setTaskAlwaysOnTop(true);
opts.setTaskOverlay(true, true);
- opts.setSplitScreenCreateMode(SPLIT_SCREEN_CREATE_MODE_BOTTOM_OR_RIGHT);
Bundle optsBundle = opts.toBundle();
// Try and merge the constructed options with a new set of options
@@ -71,7 +69,5 @@
assertTrue(restoredOpts.getTaskAlwaysOnTop());
assertTrue(restoredOpts.getTaskOverlay());
assertTrue(restoredOpts.canTaskOverlayResume());
- assertEquals(SPLIT_SCREEN_CREATE_MODE_BOTTOM_OR_RIGHT,
- restoredOpts.getSplitScreenCreateMode());
}
}
diff --git a/services/tests/wmtests/src/com/android/server/wm/ActivityRecordTests.java b/services/tests/wmtests/src/com/android/server/wm/ActivityRecordTests.java
index b50e50b..83cadf3 100644
--- a/services/tests/wmtests/src/com/android/server/wm/ActivityRecordTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/ActivityRecordTests.java
@@ -254,26 +254,26 @@
// Set and apply options for ActivityRecord. Pending options should be cleared
activity.updateOptionsLocked(activityOptions);
- activity.applyOptionsLocked();
- assertNull(activity.pendingOptions);
+ activity.applyOptionsAnimation();
+ assertNull(activity.getOptions());
// Set options for two ActivityRecords in same Task. Apply one ActivityRecord options.
// Pending options should be cleared for both ActivityRecords
ActivityRecord activity2 = new ActivityBuilder(mAtm).setTask(activity.getTask()).build();
activity2.updateOptionsLocked(activityOptions);
activity.updateOptionsLocked(activityOptions);
- activity.applyOptionsLocked();
- assertNull(activity.pendingOptions);
- assertNull(activity2.pendingOptions);
+ activity.applyOptionsAnimation();
+ assertNull(activity.getOptions());
+ assertNull(activity2.getOptions());
// Set options for two ActivityRecords in separate Tasks. Apply one ActivityRecord options.
// Pending options should be cleared for only ActivityRecord that was applied
activity2 = new ActivityBuilder(mAtm).setCreateTask(true).build();
activity2.updateOptionsLocked(activityOptions);
activity.updateOptionsLocked(activityOptions);
- activity.applyOptionsLocked();
- assertNull(activity.pendingOptions);
- assertNotNull(activity2.pendingOptions);
+ activity.applyOptionsAnimation();
+ assertNull(activity.getOptions());
+ assertNotNull(activity2.getOptions());
}
@Test
@@ -653,21 +653,21 @@
public void onAnimationStart(RemoteAnimationTarget[] apps,
RemoteAnimationTarget[] wallpapers,
IRemoteAnimationFinishedCallback finishedCallback) {
-
}
@Override
public void onAnimationCancelled() {
-
}
}, 0, 0));
activity.updateOptionsLocked(opts);
- assertNotNull(activity.takeOptionsLocked(true /* fromClient */));
- assertNotNull(activity.pendingOptions);
+ assertNotNull(activity.takeOptions());
+ assertNull(activity.getOptions());
- activity.updateOptionsLocked(ActivityOptions.makeBasic());
- assertNotNull(activity.takeOptionsLocked(false /* fromClient */));
- assertNull(activity.pendingOptions);
+ final AppTransition appTransition = activity.mDisplayContent.mAppTransition;
+ spyOn(appTransition);
+ activity.applyOptionsAnimation();
+
+ verify(appTransition).overridePendingAppTransitionRemote(any());
}
@Test
@@ -1660,8 +1660,8 @@
any() /* window */, any() /* attrs */,
anyInt() /* viewVisibility */, anyInt() /* displayId */,
any() /* requestedVisibility */, any() /* outFrame */,
- any() /* outDisplayCutout */, any() /* outInputChannel */,
- any() /* outInsetsState */, any() /* outActiveControls */);
+ any() /* outInputChannel */, any() /* outInsetsState */,
+ any() /* outActiveControls */);
mAtm.mWindowManager.mStartingSurfaceController
.createTaskSnapshotSurface(activity, snapshot);
} catch (RemoteException ignored) {
diff --git a/services/tests/wmtests/src/com/android/server/wm/DisplayPolicyLayoutTests.java b/services/tests/wmtests/src/com/android/server/wm/DisplayPolicyLayoutTests.java
index 378a0a8..0f03f68 100644
--- a/services/tests/wmtests/src/com/android/server/wm/DisplayPolicyLayoutTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/DisplayPolicyLayoutTests.java
@@ -689,7 +689,7 @@
final InsetsState outState = new InsetsState();
mDisplayPolicy.getLayoutHint(mWindow.mAttrs, null /* windowToken */, outFrame,
- outDisplayCutout, outState, true /* localClient */);
+ outState, true /* localClient */);
assertThat(outFrame, is(outState.getDisplayFrame()));
assertThat(outDisplayCutout, is(new DisplayCutout.ParcelableWrapper()));
@@ -716,8 +716,8 @@
new DisplayCutout.ParcelableWrapper();
final InsetsState outState = new InsetsState();
- mDisplayPolicy.getLayoutHint(mWindow.mAttrs, mWindow.mToken, outFrame, outDisplayCutout,
- outState, true /* localClient */);
+ mDisplayPolicy.getLayoutHint(mWindow.mAttrs, mWindow.mToken, outFrame, outState,
+ true /* localClient */);
assertThat(outFrame, is(taskBounds));
assertThat(outDisplayCutout, is(new DisplayCutout.ParcelableWrapper()));
@@ -756,8 +756,8 @@
new DisplayCutout.ParcelableWrapper();
final InsetsState outState = new InsetsState();
- mDisplayPolicy.getLayoutHint(mWindow.mAttrs, mWindow.mToken, outFrame, outDisplayCutout,
- outState, true /* localClient */);
+ mDisplayPolicy.getLayoutHint(mWindow.mAttrs, mWindow.mToken, outFrame, outState,
+ true /* localClient */);
assertThat(outFrame, is(taskBounds));
assertThat(outDisplayCutout, is(new DisplayCutout.ParcelableWrapper()));
diff --git a/services/tests/wmtests/src/com/android/server/wm/LaunchParamsControllerTests.java b/services/tests/wmtests/src/com/android/server/wm/LaunchParamsControllerTests.java
index 089fd20..61140d6 100644
--- a/services/tests/wmtests/src/com/android/server/wm/LaunchParamsControllerTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/LaunchParamsControllerTests.java
@@ -495,7 +495,7 @@
// We didn't set up the overall environment for this test, so we need to mute the side
// effect of layout passes that loosen the stable frame.
- doNothing().when(display.mDisplayContent.mDisplayFrames).onBeginLayout();
+ doNothing().when(display.mDisplayContent.mDisplayFrames).onBeginLayout(any());
return display;
}
}
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 4892ef3..93ef126b 100644
--- a/services/tests/wmtests/src/com/android/server/wm/RecentTasksTest.java
+++ b/services/tests/wmtests/src/com/android/server/wm/RecentTasksTest.java
@@ -1006,8 +1006,6 @@
assertNotRestoreTask(
() -> mAtm.setTaskWindowingMode(taskId, WINDOWING_MODE_FULLSCREEN,
false/* toTop */));
- assertNotRestoreTask(
- () -> mAtm.setTaskWindowingModeSplitScreenPrimary(taskId, false /* toTop */));
}
@Test
@@ -1144,8 +1142,6 @@
assertSecurityException(expectCallable,
() -> mAtm.moveTaskToRootTask(0, INVALID_STACK_ID, true));
assertSecurityException(expectCallable,
- () -> mAtm.setTaskWindowingModeSplitScreenPrimary(0, true));
- assertSecurityException(expectCallable,
() -> mAtm.moveTopActivityToPinnedRootTask(INVALID_STACK_ID, new Rect()));
assertSecurityException(expectCallable, () -> mAtm.getAllRootTaskInfos());
assertSecurityException(expectCallable,
diff --git a/services/tests/wmtests/src/com/android/server/wm/SizeCompatTests.java b/services/tests/wmtests/src/com/android/server/wm/SizeCompatTests.java
index c7175a0c..e190248 100644
--- a/services/tests/wmtests/src/com/android/server/wm/SizeCompatTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/SizeCompatTests.java
@@ -49,6 +49,8 @@
import android.app.ActivityManagerInternal;
import android.app.TaskStackListener;
import android.app.WindowConfiguration;
+import android.compat.testing.PlatformCompatChangeRule;
+import android.content.ComponentName;
import android.content.pm.ActivityInfo;
import android.content.res.Configuration;
import android.graphics.Rect;
@@ -58,7 +60,11 @@
import androidx.test.filters.MediumTest;
+import libcore.junit.util.compat.CoreCompatChangeRule.EnableCompatChanges;
+
+import org.junit.Rule;
import org.junit.Test;
+import org.junit.rules.TestRule;
import org.junit.runner.RunWith;
import java.util.ArrayList;
@@ -73,6 +79,9 @@
@Presubmit
@RunWith(WindowTestRunner.class)
public class SizeCompatTests extends WindowTestsBase {
+ @Rule
+ public TestRule compatChangeRule = new PlatformCompatChangeRule();
+
private Task mTask;
private ActivityRecord mActivity;
@@ -535,6 +544,26 @@
}
@Test
+ @EnableCompatChanges({ActivityInfo.FORCE_RESIZE_APP})
+ public void testNoSizeCompatWhenPerAppOverrideSet() {
+ setUpDisplaySizeWithApp(1000, 2500);
+
+ // Make the task root resizable.
+ mActivity.info.resizeMode = ActivityInfo.RESIZE_MODE_RESIZEABLE;
+
+ // Create a size compat activity on the same task.
+ final ActivityRecord activity = new ActivityBuilder(mAtm)
+ .setTask(mTask)
+ .setResizeMode(ActivityInfo.RESIZE_MODE_UNRESIZEABLE)
+ .setScreenOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT)
+ .setComponent(ComponentName.createRelative(mContext,
+ SizeCompatTests.class.getName()))
+ .setUid(android.os.Process.myUid())
+ .build();
+ assertFalse(activity.shouldUseSizeCompatMode());
+ }
+
+ @Test
public void testLaunchWithFixedRotationTransform() {
final int dw = 1000;
final int dh = 2500;
diff --git a/services/tests/wmtests/src/com/android/server/wm/TaskSnapshotSurfaceTest.java b/services/tests/wmtests/src/com/android/server/wm/TaskSnapshotSurfaceTest.java
index eb3a5e0..d49956a 100644
--- a/services/tests/wmtests/src/com/android/server/wm/TaskSnapshotSurfaceTest.java
+++ b/services/tests/wmtests/src/com/android/server/wm/TaskSnapshotSurfaceTest.java
@@ -37,7 +37,6 @@
import static org.mockito.Matchers.eq;
import android.app.ActivityManager.TaskDescription;
-import android.window.TaskSnapshot;
import android.content.ComponentName;
import android.graphics.Canvas;
import android.graphics.Color;
@@ -52,6 +51,7 @@
import android.view.Surface;
import android.view.SurfaceControl;
import android.view.WindowManager;
+import android.window.TaskSnapshot;
import androidx.test.filters.SmallTest;
@@ -145,7 +145,7 @@
assertThat(surface).isNotNull();
verify(session).addToDisplay(any(), argThat(this::isTrustedOverlay), anyInt(), anyInt(),
- any(), any(), any(), any(), any(), any());
+ any(), any(), any(), any(), any());
}
@Test
diff --git a/services/tests/wmtests/src/com/android/server/wm/WindowFrameTests.java b/services/tests/wmtests/src/com/android/server/wm/WindowFrameTests.java
index 4a6906b..1607f01 100644
--- a/services/tests/wmtests/src/com/android/server/wm/WindowFrameTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/WindowFrameTests.java
@@ -19,8 +19,6 @@
import static android.app.WindowConfiguration.WINDOWING_MODE_FREEFORM;
import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN;
import static android.app.WindowConfiguration.WINDOWING_MODE_SPLIT_SCREEN_SECONDARY;
-import static android.view.DisplayCutout.BOUNDS_POSITION_TOP;
-import static android.view.DisplayCutout.fromBoundingRect;
import static android.view.InsetsState.ITYPE_IME;
import static android.view.InsetsState.ITYPE_STATUS_BAR;
import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION;
@@ -42,8 +40,6 @@
import androidx.test.filters.FlakyTest;
import androidx.test.filters.SmallTest;
-import com.android.server.wm.utils.WmDisplayCutout;
-
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
@@ -258,30 +254,6 @@
}
@Test
- @FlakyTest(bugId = 130388666)
- public void testDisplayCutout() {
- // Regular fullscreen task and window
- WindowState w = createWindow();
- w.mAttrs.gravity = Gravity.LEFT | Gravity.TOP;
-
- final Rect pf = new Rect(0, 0, 1000, 2000);
- // Create a display cutout of size 50x50, aligned top-center
- final WmDisplayCutout cutout = WmDisplayCutout.computeSafeInsets(
- fromBoundingRect(500, 0, 550, 50, BOUNDS_POSITION_TOP),
- pf.width(), pf.height());
-
- final WindowFrames windowFrames = w.getWindowFrames();
- windowFrames.setFrames(pf, pf);
- windowFrames.setDisplayCutout(cutout);
- w.computeFrame();
-
- assertEquals(w.getWmDisplayCutout().getDisplayCutout().getSafeInsetTop(), 50);
- assertEquals(w.getWmDisplayCutout().getDisplayCutout().getSafeInsetBottom(), 0);
- assertEquals(w.getWmDisplayCutout().getDisplayCutout().getSafeInsetLeft(), 0);
- assertEquals(w.getWmDisplayCutout().getDisplayCutout().getSafeInsetRight(), 0);
- }
-
- @Test
public void testFreeformContentInsets() {
removeGlobalMinSizeRestriction();
// fullscreen task doesn't use bounds for computeFrame
diff --git a/services/tests/wmtests/src/com/android/server/wm/WindowStateTests.java b/services/tests/wmtests/src/com/android/server/wm/WindowStateTests.java
index 5ceb4ca0..7db2fc9 100644
--- a/services/tests/wmtests/src/com/android/server/wm/WindowStateTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/WindowStateTests.java
@@ -67,14 +67,11 @@
import static org.mockito.Mockito.clearInvocations;
import static org.mockito.Mockito.when;
-import android.graphics.Insets;
import android.graphics.Matrix;
import android.graphics.Rect;
import android.os.IBinder;
import android.os.RemoteException;
import android.platform.test.annotations.Presubmit;
-import android.util.Size;
-import android.view.DisplayCutout;
import android.view.InputWindowHandle;
import android.view.InsetsState;
import android.view.SurfaceControl;
@@ -82,8 +79,6 @@
import androidx.test.filters.SmallTest;
-import com.android.server.wm.utils.WmDisplayCutout;
-
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
@@ -527,24 +522,6 @@
}
@Test
- public void testDisplayCutoutIsCalculatedRelativeToFrame() {
- final WindowState app = createWindow(null, TYPE_APPLICATION, "app");
- WindowFrames wf = app.getWindowFrames();
- wf.mParentFrame.set(7, 10, 185, 380);
- wf.mDisplayFrame.set(wf.mParentFrame);
- final DisplayCutout cutout = new DisplayCutout(
- Insets.of(0, 15, 0, 22) /* safeInset */,
- null /* boundLeft */,
- new Rect(95, 0, 105, 15),
- null /* boundRight */,
- new Rect(95, 378, 105, 400));
- wf.setDisplayCutout(new WmDisplayCutout(cutout, new Size(200, 400)));
-
- app.computeFrame();
- assertThat(app.getWmDisplayCutout().getDisplayCutout(), is(cutout.inset(7, 10, 5, 20)));
- }
-
- @Test
public void testVisibilityChangeSwitchUser() {
final WindowState window = createWindow(null, TYPE_APPLICATION, "app");
window.mHasSurface = true;
diff --git a/services/tests/wmtests/src/com/android/server/wm/utils/WmDisplayCutoutTest.java b/services/tests/wmtests/src/com/android/server/wm/utils/WmDisplayCutoutTest.java
index a283476..39976a5 100644
--- a/services/tests/wmtests/src/com/android/server/wm/utils/WmDisplayCutoutTest.java
+++ b/services/tests/wmtests/src/com/android/server/wm/utils/WmDisplayCutoutTest.java
@@ -23,10 +23,8 @@
import static android.view.DisplayCutout.NO_CUTOUT;
import static android.view.DisplayCutout.fromBoundingRect;
-import static org.hamcrest.Matchers.equalTo;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotEquals;
-import static org.junit.Assert.assertThat;
import android.graphics.Insets;
import android.graphics.Rect;
@@ -54,52 +52,6 @@
null /* boundRight */, null /* boundBottom */);
@Test
- public void calculateRelativeTo_top() {
- WmDisplayCutout cutout = WmDisplayCutout.computeSafeInsets(
- fromBoundingRect(0, 0, 100, 20, BOUNDS_POSITION_TOP), 200, 400)
- .calculateRelativeTo(new Rect(5, 5, 95, 195));
-
- assertEquals(new Rect(0, 15, 0, 0), cutout.getDisplayCutout().getSafeInsets());
- }
-
- @Test
- public void calculateRelativeTo_left() {
- WmDisplayCutout cutout = WmDisplayCutout.computeSafeInsets(
- fromBoundingRect(0, 0, 20, 100, BOUNDS_POSITION_LEFT), 400, 200)
- .calculateRelativeTo(new Rect(5, 5, 195, 95));
-
- assertEquals(new Rect(15, 0, 0, 0), cutout.getDisplayCutout().getSafeInsets());
- }
-
- @Test
- public void calculateRelativeTo_bottom() {
- WmDisplayCutout cutout = WmDisplayCutout.computeSafeInsets(
- fromBoundingRect(0, 180, 100, 200, BOUNDS_POSITION_BOTTOM), 100, 200)
- .calculateRelativeTo(new Rect(5, 5, 95, 195));
-
- assertEquals(new Rect(0, 0, 0, 15), cutout.getDisplayCutout().getSafeInsets());
- }
-
- @Test
- public void calculateRelativeTo_right() {
- WmDisplayCutout cutout = WmDisplayCutout.computeSafeInsets(
- fromBoundingRect(180, 0, 200, 100, BOUNDS_POSITION_RIGHT), 200, 100)
- .calculateRelativeTo(new Rect(5, 5, 195, 95));
-
- assertEquals(new Rect(0, 0, 15, 0), cutout.getDisplayCutout().getSafeInsets());
- }
-
- @Test
- public void calculateRelativeTo_bounds() {
- WmDisplayCutout cutout = WmDisplayCutout.computeSafeInsets(
- fromBoundingRect(0, 0, 100, 20, BOUNDS_POSITION_TOP), 200, 400)
- .calculateRelativeTo(new Rect(5, 10, 95, 180));
-
- assertThat(cutout.getDisplayCutout().getBoundingRectTop(),
- equalTo(new Rect(-5, -10, 95, 10)));
- }
-
- @Test
public void computeSafeInsets_cutoutTop() {
WmDisplayCutout cutout = WmDisplayCutout.computeSafeInsets(
fromBoundingRect(80, 0, 120, 20, BOUNDS_POSITION_TOP), 200, 400);
diff --git a/telephony/java/android/telephony/ims/ImsCallSession.java b/telephony/java/android/telephony/ims/ImsCallSession.java
index a3efb79..0aff997 100755
--- a/telephony/java/android/telephony/ims/ImsCallSession.java
+++ b/telephony/java/android/telephony/ims/ImsCallSession.java
@@ -101,10 +101,29 @@
*/
public static class Listener {
/**
- * Called when a request is sent out to initiate a new session
- * and 1xx response is received from the network.
+ * Called when the session is initiating.
*
- * @param session the session object that carries out the IMS session
+ * see: {@link ImsCallSessionListener#callSessionInitiating(ImsCallProfile)}
+ */
+ public void callSessionInitiating(ImsCallSession session,
+ ImsCallProfile profile) {
+ // no-op
+ }
+
+ /**
+ * Called when the session failed before initiating was called.
+ *
+ * see: {@link ImsCallSessionListener#callSessionInitiatingFailed(ImsReasonInfo)}
+ */
+ public void callSessionInitiatingFailed(ImsCallSession session,
+ ImsReasonInfo reasonInfo) {
+ // no-op
+ }
+
+ /**
+ * Called when the session is progressing.
+ *
+ * see: {@link ImsCallSessionListener#callSessionProgressing(ImsStreamMediaProfile)}
*/
public void callSessionProgressing(ImsCallSession session,
ImsStreamMediaProfile profile) {
@@ -1179,6 +1198,13 @@
* Notifies the result of the basic session operation (setup / terminate).
*/
@Override
+ public void callSessionInitiating(ImsCallProfile profile) {
+ if (mListener != null) {
+ mListener.callSessionInitiating(ImsCallSession.this, profile);
+ }
+ }
+
+ @Override
public void callSessionProgressing(ImsStreamMediaProfile profile) {
if (mListener != null) {
mListener.callSessionProgressing(ImsCallSession.this, profile);
@@ -1193,6 +1219,13 @@
}
@Override
+ public void callSessionInitiatingFailed(ImsReasonInfo reasonInfo) {
+ if (mListener != null) {
+ mListener.callSessionStartFailed(ImsCallSession.this, reasonInfo);
+ }
+ }
+
+ @Override
public void callSessionInitiatedFailed(ImsReasonInfo reasonInfo) {
if (mListener != null) {
mListener.callSessionStartFailed(ImsCallSession.this, reasonInfo);
diff --git a/telephony/java/android/telephony/ims/ImsCallSessionListener.java b/telephony/java/android/telephony/ims/ImsCallSessionListener.java
index 86bb5d9..db99acf 100644
--- a/telephony/java/android/telephony/ims/ImsCallSessionListener.java
+++ b/telephony/java/android/telephony/ims/ImsCallSessionListener.java
@@ -53,8 +53,45 @@
}
/**
- * A request has been sent out to initiate a new IMS call session and a 1xx response has been
- * received from the network.
+ * Called when the network first begins to establish the call session and is now connecting
+ * to the remote party. This must be called once after {@link ImsCallSessionImplBase#start} and
+ * before any other method on this listener. After this is called,
+ * {@link #callSessionProgressing(ImsStreamMediaProfile)} must be called to communicate any
+ * further updates.
+ * <p/>
+ * Once this is called, {@link #callSessionTerminated} must be called
+ * to end the call session. In the event that the session failed before the remote party
+ * was contacted, {@link #callSessionInitiatingFailed} must be called.
+ *
+ * @param profile the associated {@link ImsCallProfile}.
+ */
+ public void callSessionInitiating(@NonNull ImsCallProfile profile) {
+ try {
+ mListener.callSessionInitiating(profile);
+ } catch (RemoteException e) {
+ e.rethrowFromSystemServer();
+ }
+ }
+
+ /**
+ * The IMS call session establishment has failed while initiating.
+ *
+ * @param reasonInfo {@link ImsReasonInfo} detailing the reason of the IMS call session
+ * establishment failure.
+ */
+ public void callSessionInitiatingFailed(@NonNull ImsReasonInfo reasonInfo) {
+ try {
+ mListener.callSessionInitiatingFailed(reasonInfo);
+ } catch (RemoteException e) {
+ e.rethrowFromSystemServer();
+ }
+ }
+
+ /**
+ * Called after the network has contacted the remote party and the call state should move to
+ * ALERTING.
+ *
+ * @param profile the associated {@link ImsCallProfile}.
*/
public void callSessionProgressing(ImsStreamMediaProfile profile) {
try {
@@ -65,7 +102,8 @@
}
/**
- * The IMS call session has been initiated.
+ * Called once the outgoing IMS call session has been begun between the local and remote party.
+ * The call state should move to ACTIVE.
*
* @param profile the associated {@link ImsCallProfile}.
*/
@@ -82,7 +120,12 @@
*
* @param reasonInfo {@link ImsReasonInfo} detailing the reason of the IMS call session
* establishment failure.
+ * @deprecated {@link #callSessionInitiated(ImsCallProfile)} is called immediately after
+ * the session is first started which meant that there was no time in which a call to this
+ * method was technically valid. This method is replaced starting Android S in favor of
+ * {@link #callSessionInitiatingFailed(ImsReasonInfo)}.
*/
+ @Deprecated
public void callSessionInitiatedFailed(ImsReasonInfo reasonInfo) {
try {
mListener.callSessionInitiatedFailed(reasonInfo);
diff --git a/telephony/java/android/telephony/ims/aidl/IImsCallSessionListener.aidl b/telephony/java/android/telephony/ims/aidl/IImsCallSessionListener.aidl
index ed895b7..ed03752 100644
--- a/telephony/java/android/telephony/ims/aidl/IImsCallSessionListener.aidl
+++ b/telephony/java/android/telephony/ims/aidl/IImsCallSessionListener.aidl
@@ -37,6 +37,8 @@
/**
* Notifies the result of the basic session operation (setup / terminate).
*/
+ void callSessionInitiating(in ImsCallProfile profile);
+ void callSessionInitiatingFailed(in ImsReasonInfo reasonInfo);
void callSessionProgressing(in ImsStreamMediaProfile profile);
void callSessionInitiated(in ImsCallProfile profile);
void callSessionInitiatedFailed(in ImsReasonInfo reasonInfo);
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppColdTest.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppColdTest.kt
index d81c24d..ba7770d 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppColdTest.kt
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppColdTest.kt
@@ -107,7 +107,7 @@
configuration.endRotation)
navBarLayerIsAlwaysVisible(enabled = false)
statusBarLayerIsAlwaysVisible(enabled = false)
- visibleLayersShownMoreThanOneConsecutiveEntry(bugId = 174541970)
+ visibleLayersShownMoreThanOneConsecutiveEntry()
appLayerReplacesWallpaperLayer(testApp.`package`)
}
diff --git a/wifi/MOVED.txt b/wifi/MOVED.txt
new file mode 100644
index 0000000..6ffb23c
--- /dev/null
+++ b/wifi/MOVED.txt
@@ -0,0 +1,8 @@
+Source code and tests for Wifi module APIs have moved to
+packages/modules/Wifi/framework.
+
+- frameworks/base/wifi/java -> packages/modules/Wifi/framework/java
+- frameworks/base/wifi/tests -> packages/modules/Wifi/framework/tests
+
+What remains in frameworks/base/wifi are Wifi APIs that
+are not part of the Wifi module.