diff options
74 files changed, 2107 insertions, 1620 deletions
diff --git a/Android.bp b/Android.bp index 2c5fc4e11e39..0210bb3c1323 100644 --- a/Android.bp +++ b/Android.bp @@ -451,6 +451,7 @@ java_defaults { "location/java/android/location/IGpsGeofenceHardware.aidl", "location/java/android/location/INetInitiatedListener.aidl", "location/java/com/android/internal/location/ILocationProvider.aidl", + "location/java/com/android/internal/location/ILocationProviderManager.aidl", "media/java/android/media/IAudioFocusDispatcher.aidl", "media/java/android/media/IAudioRoutesObserver.aidl", "media/java/android/media/IAudioService.aidl", diff --git a/api/current.txt b/api/current.txt index 1b6229efc0dd..931b9facf209 100644 --- a/api/current.txt +++ b/api/current.txt @@ -22741,8 +22741,8 @@ package android.location { method public boolean addNmeaListener(android.location.OnNmeaMessageListener, android.os.Handler); method public void addProximityAlert(double, double, float, long, android.app.PendingIntent); method public void addTestProvider(java.lang.String, boolean, boolean, boolean, boolean, boolean, boolean, boolean, int, int); - method public void clearTestProviderEnabled(java.lang.String); - method public void clearTestProviderLocation(java.lang.String); + method public deprecated void clearTestProviderEnabled(java.lang.String); + method public deprecated void clearTestProviderLocation(java.lang.String); method public deprecated void clearTestProviderStatus(java.lang.String); method public java.util.List<java.lang.String> getAllProviders(); method public java.lang.String getBestProvider(android.location.Criteria, boolean); @@ -22954,6 +22954,7 @@ package android.media { method public int getChannelIndexMask(); method public int getChannelMask(); method public int getEncoding(); + method public int getFrameSizeInBytes(); method public int getSampleRate(); method public void writeToParcel(android.os.Parcel, int); field public static final deprecated int CHANNEL_CONFIGURATION_DEFAULT = 1; // 0x1 @@ -40467,6 +40468,7 @@ package android.service.autofill { method public android.service.autofill.FillResponse.Builder setHeader(android.widget.RemoteViews); method public android.service.autofill.FillResponse.Builder setIgnoredIds(android.view.autofill.AutofillId...); method public android.service.autofill.FillResponse.Builder setSaveInfo(android.service.autofill.SaveInfo); + method public android.service.autofill.FillResponse.Builder setUserData(android.service.autofill.UserData); } public final class ImageTransformation implements android.os.Parcelable android.service.autofill.Transformation { @@ -43785,10 +43787,10 @@ package android.telephony { method public static java.lang.String getStrippedReversed(java.lang.String); method public static final boolean is12Key(char); method public static final boolean isDialable(char); - method public static boolean isEmergencyNumber(java.lang.String); + method public static deprecated boolean isEmergencyNumber(java.lang.String); method public static boolean isGlobalPhoneNumber(java.lang.String); method public static boolean isISODigit(char); - method public static boolean isLocalEmergencyNumber(android.content.Context, java.lang.String); + method public static deprecated boolean isLocalEmergencyNumber(android.content.Context, java.lang.String); method public static final boolean isNonSeparator(char); method public static final boolean isReallyDialable(char); method public static final boolean isStartsPostDial(char); @@ -44496,11 +44498,13 @@ package android.telephony.emergency { method public java.util.List<java.lang.Integer> getEmergencyNumberSources(); method public java.util.List<java.lang.Integer> getEmergencyServiceCategories(); method public int getEmergencyServiceCategoryBitmask(); + method public java.lang.String getMnc(); method public java.lang.String getNumber(); method public boolean isFromSources(int); method public boolean isInEmergencyServiceCategories(int); method public void writeToParcel(android.os.Parcel, int); field public static final android.os.Parcelable.Creator<android.telephony.emergency.EmergencyNumber> CREATOR; + field public static final int EMERGENCY_NUMBER_SOURCE_DATABASE = 16; // 0x10 field public static final int EMERGENCY_NUMBER_SOURCE_DEFAULT = 8; // 0x8 field public static final int EMERGENCY_NUMBER_SOURCE_MODEM_CONFIG = 4; // 0x4 field public static final int EMERGENCY_NUMBER_SOURCE_NETWORK_SIGNALING = 1; // 0x1 @@ -52483,6 +52487,7 @@ package android.view.textclassifier { public static final class ConversationActions.Request implements android.os.Parcelable { method public int describeContents(); + method public java.lang.String getCallingPackageName(); method public java.util.List<android.view.textclassifier.ConversationActions.Message> getConversation(); method public java.util.List<java.lang.String> getHints(); method public int getMaxSuggestions(); @@ -52596,6 +52601,7 @@ package android.view.textclassifier { public static final class TextClassification.Request implements android.os.Parcelable { method public int describeContents(); + method public java.lang.String getCallingPackageName(); method public android.os.LocaleList getDefaultLocales(); method public int getEndIndex(); method public android.os.Bundle getExtras(); @@ -52713,6 +52719,7 @@ package android.view.textclassifier { public static final class TextLanguage.Request implements android.os.Parcelable { method public int describeContents(); + method public java.lang.String getCallingPackageName(); method public android.os.Bundle getExtras(); method public java.lang.CharSequence getText(); method public void writeToParcel(android.os.Parcel, int); @@ -52744,6 +52751,7 @@ package android.view.textclassifier { public static final class TextLinks.Builder { ctor public TextLinks.Builder(java.lang.String); method public android.view.textclassifier.TextLinks.Builder addLink(int, int, java.util.Map<java.lang.String, java.lang.Float>); + method public android.view.textclassifier.TextLinks.Builder addLink(int, int, java.util.Map<java.lang.String, java.lang.Float>, android.os.Bundle); method public android.view.textclassifier.TextLinks build(); method public android.view.textclassifier.TextLinks.Builder clearTextLinks(); method public android.view.textclassifier.TextLinks.Builder setExtras(android.os.Bundle); @@ -52751,6 +52759,7 @@ package android.view.textclassifier { public static final class TextLinks.Request implements android.os.Parcelable { method public int describeContents(); + method public java.lang.String getCallingPackageName(); method public android.os.LocaleList getDefaultLocales(); method public android.view.textclassifier.TextClassifier.EntityConfig getEntityConfig(); method public android.os.Bundle getExtras(); @@ -52773,6 +52782,7 @@ package android.view.textclassifier { method public int getEnd(); method public java.lang.String getEntity(int); method public int getEntityCount(); + method public android.os.Bundle getExtras(); method public int getStart(); method public void writeToParcel(android.os.Parcel, int); field public static final android.os.Parcelable.Creator<android.view.textclassifier.TextLinks.TextLink> CREATOR; @@ -52807,6 +52817,7 @@ package android.view.textclassifier { public static final class TextSelection.Request implements android.os.Parcelable { method public int describeContents(); + method public java.lang.String getCallingPackageName(); method public android.os.LocaleList getDefaultLocales(); method public int getEndIndex(); method public android.os.Bundle getExtras(); diff --git a/api/system-current.txt b/api/system-current.txt index 7d30529a9ab1..29089b3e908a 100644 --- a/api/system-current.txt +++ b/api/system-current.txt @@ -7,6 +7,7 @@ package android { field public static final java.lang.String ACCESS_CHECKIN_PROPERTIES = "android.permission.ACCESS_CHECKIN_PROPERTIES"; field public static final java.lang.String ACCESS_DRM_CERTIFICATES = "android.permission.ACCESS_DRM_CERTIFICATES"; field public static final deprecated java.lang.String ACCESS_FM_RADIO = "android.permission.ACCESS_FM_RADIO"; + field public static final java.lang.String ACCESS_INSTANT_APPS = "android.permission.ACCESS_INSTANT_APPS"; field public static final java.lang.String ACCESS_MOCK_LOCATION = "android.permission.ACCESS_MOCK_LOCATION"; field public static final java.lang.String ACCESS_MTP = "android.permission.ACCESS_MTP"; field public static final java.lang.String ACCESS_NETWORK_CONDITIONS = "android.permission.ACCESS_NETWORK_CONDITIONS"; @@ -315,7 +316,6 @@ package android.app { method public android.app.AppOpsManager.HistoricalPackageOps getHistoricalPackagesOps(int, java.lang.String, java.lang.String[], long, long); method public static java.lang.String[] getOpStrs(); method public java.util.List<android.app.AppOpsManager.PackageOps> getOpsForPackage(int, java.lang.String, int[]); - method public java.util.List<android.app.AppOpsManager.PackageOps> getPackagesForOpStrs(java.lang.String[]); method public static int opToDefaultMode(java.lang.String); method public static java.lang.String opToPermission(java.lang.String); method public void setMode(java.lang.String, int, java.lang.String, int); @@ -1253,6 +1253,7 @@ package android.content.pm { method public abstract java.util.List<android.content.pm.IntentFilterVerificationInfo> getIntentFilterVerifications(java.lang.String); method public abstract int getIntentVerificationStatusAsUser(java.lang.String, int); method public abstract int getPermissionFlags(java.lang.String, java.lang.String, android.os.UserHandle); + method public java.lang.String getWellbeingPackageName(); method public abstract void grantRuntimePermission(java.lang.String, java.lang.String, android.os.UserHandle); method public abstract int installExistingPackage(java.lang.String) throws android.content.pm.PackageManager.NameNotFoundException; method public abstract int installExistingPackage(java.lang.String, int) throws android.content.pm.PackageManager.NameNotFoundException; @@ -1355,6 +1356,7 @@ package android.content.pm { field public static final int FLAG_REMOVED = 2; // 0x2 field public static final int PROTECTION_FLAG_OEM = 16384; // 0x4000 field public static final int PROTECTION_FLAG_SYSTEM_TEXT_CLASSIFIER = 65536; // 0x10000 + field public static final int PROTECTION_FLAG_WELLBEING = 131072; // 0x20000 field public java.lang.String backgroundPermission; field public int requestRes; } @@ -5968,6 +5970,7 @@ package android.telephony { method public int getVoiceActivationState(); method public boolean handlePinMmi(java.lang.String); method public boolean handlePinMmiForSubscriber(int, java.lang.String); + method public boolean isCurrentPotentialEmergencyNumber(java.lang.String); method public boolean isDataConnectivityPossible(); method public deprecated boolean isIdle(); method public deprecated boolean isOffhook(); diff --git a/api/test-current.txt b/api/test-current.txt index dff3f28721d5..5bedc7244430 100644 --- a/api/test-current.txt +++ b/api/test-current.txt @@ -374,6 +374,7 @@ package android.content.pm { public class PermissionInfo extends android.content.pm.PackageItemInfo implements android.os.Parcelable { field public static final int PROTECTION_FLAG_SYSTEM_TEXT_CLASSIFIER = 65536; // 0x10000 field public static final int PROTECTION_FLAG_VENDOR_PRIVILEGED = 32768; // 0x8000 + field public static final int PROTECTION_FLAG_WELLBEING = 131072; // 0x20000 field public java.lang.String backgroundPermission; } diff --git a/config/hiddenapi-greylist.txt b/config/hiddenapi-greylist.txt index 01c70286cff3..56dc4c1c0710 100644 --- a/config/hiddenapi-greylist.txt +++ b/config/hiddenapi-greylist.txt @@ -1849,13 +1849,16 @@ Lcom/android/internal/location/GpsNetInitiatedHandler;->handleNiNotification(Lco Lcom/android/internal/location/GpsNetInitiatedHandler;->mIsHexInput:Z Lcom/android/internal/location/ILocationProvider$Stub;-><init>()V Lcom/android/internal/location/ILocationProvider$Stub;->asInterface(Landroid/os/IBinder;)Lcom/android/internal/location/ILocationProvider; -Lcom/android/internal/location/ILocationProvider;->disable()V -Lcom/android/internal/location/ILocationProvider;->enable()V -Lcom/android/internal/location/ILocationProvider;->getProperties()Lcom/android/internal/location/ProviderProperties; Lcom/android/internal/location/ILocationProvider;->getStatus(Landroid/os/Bundle;)I Lcom/android/internal/location/ILocationProvider;->getStatusUpdateTime()J -Lcom/android/internal/location/ILocationProvider;->sendExtraCommand(Ljava/lang/String;Landroid/os/Bundle;)Z +Lcom/android/internal/location/ILocationProvider;->sendExtraCommand(Ljava/lang/String;Landroid/os/Bundle;)V +Lcom/android/internal/location/ILocationProvider;->setLocationProviderManager(Lcom/android/internal/location/ILocationProviderManager;)V Lcom/android/internal/location/ILocationProvider;->setRequest(Lcom/android/internal/location/ProviderRequest;Landroid/os/WorkSource;)V +Lcom/android/internal/location/ILocationProviderManager$Stub;-><init>()V +Lcom/android/internal/location/ILocationProviderManager$Stub;->asInterface(Landroid/os/IBinder;)Lcom/android/internal/location/ILocationProviderManager; +Lcom/android/internal/location/ILocationProviderManager;->onReportLocation(Landroid/location/Location;)V +Lcom/android/internal/location/ILocationProviderManager;->onSetEnabled(Z)V +Lcom/android/internal/location/ILocationProviderManager;->onSetProperties(Lcom/android/internal/location/ProviderProperties;)V Lcom/android/internal/logging/MetricsLogger;-><init>()V Lcom/android/internal/net/LegacyVpnInfo;-><init>()V Lcom/android/internal/net/VpnConfig;-><init>()V diff --git a/core/java/android/app/AppOpsManager.java b/core/java/android/app/AppOpsManager.java index f2fb33fef466..6905cb5cea73 100644 --- a/core/java/android/app/AppOpsManager.java +++ b/core/java/android/app/AppOpsManager.java @@ -2502,30 +2502,6 @@ public class AppOpsManager { } /** - * Retrieve current operation state for all applications. - * - * @param ops The set of operations you are interested in, or null if you want all of them. - * @hide - */ - @RequiresPermission(android.Manifest.permission.GET_APP_OPS_STATS) - @SystemApi - public List<AppOpsManager.PackageOps> getPackagesForOpStrs(String[] ops) { - if (ops == null) { - return getPackagesForOps(null); - } - final int[] opCodes = new int[ops.length]; - for (int i = 0; i < ops.length; ++i) { - final Integer opCode = sOpStrToOp.get(ops[i]); - if (opCode == null) { - opCodes[i] = OP_NONE; - } else { - opCodes[i] = opCode; - } - } - return getPackagesForOps(opCodes); - } - - /** * Retrieve current operation state for one application. * * @param uid The uid of the application of interest. diff --git a/core/java/android/app/ApplicationPackageManager.java b/core/java/android/app/ApplicationPackageManager.java index 7312b2c8163e..67d9ad6e93c6 100644 --- a/core/java/android/app/ApplicationPackageManager.java +++ b/core/java/android/app/ApplicationPackageManager.java @@ -2974,6 +2974,15 @@ public class ApplicationPackageManager extends PackageManager { } @Override + public String getWellbeingPackageName() { + try { + return mPM.getWellbeingPackageName(); + } catch (RemoteException e) { + throw e.rethrowAsRuntimeException(); + } + } + + @Override public boolean isPackageStateProtected(String packageName, int userId) { try { return mPM.isPackageStateProtected(packageName, userId); diff --git a/core/java/android/app/UiAutomationConnection.java b/core/java/android/app/UiAutomationConnection.java index dc2f9838785c..31521a369a4c 100644 --- a/core/java/android/app/UiAutomationConnection.java +++ b/core/java/android/app/UiAutomationConnection.java @@ -331,7 +331,7 @@ public final class UiAutomationConnection extends IUiAutomationConnection.Stub { writeTo.flush(); } } catch (IOException ioe) { - throw new RuntimeException("Error while reading/writing ", ioe); + Log.w(TAG, "Error while reading/writing to streams"); } finally { IoUtils.closeQuietly(readFrom); IoUtils.closeQuietly(writeTo); diff --git a/core/java/android/content/pm/IPackageManager.aidl b/core/java/android/content/pm/IPackageManager.aidl index dbea821fab2b..eea2b8873fe7 100644 --- a/core/java/android/content/pm/IPackageManager.aidl +++ b/core/java/android/content/pm/IPackageManager.aidl @@ -675,6 +675,8 @@ interface IPackageManager { String getSystemTextClassifierPackageName(); + String getWellbeingPackageName(); + boolean isPackageStateProtected(String packageName, int userId); void sendDeviceCustomizationReadyBroadcast(); diff --git a/core/java/android/content/pm/PackageManager.java b/core/java/android/content/pm/PackageManager.java index f40be84b180b..0150f6a2765d 100644 --- a/core/java/android/content/pm/PackageManager.java +++ b/core/java/android/content/pm/PackageManager.java @@ -6434,6 +6434,17 @@ public abstract class PackageManager { } /** + * @return the wellbeing app package name, or null if it's not defined by the OEM. + * + * @hide + */ + @SystemApi + public String getWellbeingPackageName() { + throw new UnsupportedOperationException( + "getWellbeingPackageName not implemented in subclass"); + } + + /** * @return whether a given package's state is protected, e.g. package cannot be disabled, * suspended, hidden or force stopped. * diff --git a/core/java/android/content/pm/PackageManagerInternal.java b/core/java/android/content/pm/PackageManagerInternal.java index b49c4476e82d..43c02228499e 100644 --- a/core/java/android/content/pm/PackageManagerInternal.java +++ b/core/java/android/content/pm/PackageManagerInternal.java @@ -53,6 +53,7 @@ public abstract class PackageManagerInternal { public static final int PACKAGE_BROWSER = 4; public static final int PACKAGE_SYSTEM_TEXT_CLASSIFIER = 5; public static final int PACKAGE_PERMISSION_CONTROLLER = 6; + public static final int PACKAGE_WELLBEING = 7; @IntDef(value = { PACKAGE_SYSTEM, PACKAGE_SETUP_WIZARD, @@ -61,6 +62,7 @@ public abstract class PackageManagerInternal { PACKAGE_BROWSER, PACKAGE_SYSTEM_TEXT_CLASSIFIER, PACKAGE_PERMISSION_CONTROLLER, + PACKAGE_WELLBEING, }) @Retention(RetentionPolicy.SOURCE) public @interface KnownPackage {} diff --git a/core/java/android/content/pm/PermissionInfo.java b/core/java/android/content/pm/PermissionInfo.java index d9d6b5f87eac..20997d6c0d11 100644 --- a/core/java/android/content/pm/PermissionInfo.java +++ b/core/java/android/content/pm/PermissionInfo.java @@ -181,6 +181,17 @@ public class PermissionInfo extends PackageItemInfo implements Parcelable { @TestApi public static final int PROTECTION_FLAG_SYSTEM_TEXT_CLASSIFIER = 0x10000; + /** + * Additional flag for {${link #protectionLevel}, corresponding + * to the <code>wellbeing</code> value of + * {@link android.R.attr#protectionLevel}. + * + * @hide + */ + @SystemApi + @TestApi + public static final int PROTECTION_FLAG_WELLBEING = 0x20000; + /** @hide */ @IntDef(flag = true, prefix = { "PROTECTION_FLAG_" }, value = { PROTECTION_FLAG_PRIVILEGED, @@ -197,6 +208,7 @@ public class PermissionInfo extends PackageItemInfo implements Parcelable { PROTECTION_FLAG_OEM, PROTECTION_FLAG_VENDOR_PRIVILEGED, PROTECTION_FLAG_SYSTEM_TEXT_CLASSIFIER, + PROTECTION_FLAG_WELLBEING, }) @Retention(RetentionPolicy.SOURCE) public @interface ProtectionFlags {} @@ -386,6 +398,9 @@ public class PermissionInfo extends PackageItemInfo implements Parcelable { if ((level & PermissionInfo.PROTECTION_FLAG_SYSTEM_TEXT_CLASSIFIER) != 0) { protLevel += "|textClassifier"; } + if ((level & PermissionInfo.PROTECTION_FLAG_WELLBEING) != 0) { + protLevel += "|wellbeing"; + } return protLevel; } diff --git a/core/java/android/service/autofill/AutofillFieldClassificationService.java b/core/java/android/service/autofill/AutofillFieldClassificationService.java index 1cd76d2e9ec9..bd3c3d3927a7 100644 --- a/core/java/android/service/autofill/AutofillFieldClassificationService.java +++ b/core/java/android/service/autofill/AutofillFieldClassificationService.java @@ -175,7 +175,7 @@ public abstract class AutofillFieldClassificationService extends Service { public float[][] onGetScores(@Nullable String algorithm, @Nullable Bundle algorithmOptions, @NonNull List<AutofillValue> actualValues, @NonNull List<String> userDataValues) { - Log.e(TAG, "service implementation (" + getClass() + " does not implement onGetScore()"); + Log.e(TAG, "service implementation (" + getClass() + " does not implement onGetScores()"); return null; } diff --git a/core/java/android/service/autofill/FillResponse.java b/core/java/android/service/autofill/FillResponse.java index 7bf1f83f6bd8..d408e9a6c3b1 100644 --- a/core/java/android/service/autofill/FillResponse.java +++ b/core/java/android/service/autofill/FillResponse.java @@ -84,6 +84,7 @@ public final class FillResponse implements Parcelable { private final @Nullable AutofillId[] mFieldClassificationIds; private final int mFlags; private int mRequestId; + private final @Nullable UserData mUserData; private FillResponse(@NonNull Builder builder) { mDatasets = (builder.mDatasets != null) ? new ParceledListSlice<>(builder.mDatasets) : null; @@ -99,6 +100,7 @@ public final class FillResponse implements Parcelable { mFieldClassificationIds = builder.mFieldClassificationIds; mFlags = builder.mFlags; mRequestId = INVALID_REQUEST_ID; + mUserData = builder.mUserData; } /** @hide */ @@ -157,6 +159,11 @@ public final class FillResponse implements Parcelable { } /** @hide */ + public @Nullable UserData getUserData() { + return mUserData; + } + + /** @hide */ @TestApi public int getFlags() { return mFlags; @@ -198,6 +205,7 @@ public final class FillResponse implements Parcelable { private AutofillId[] mFieldClassificationIds; private int mFlags; private boolean mDestroyed; + private UserData mUserData; /** * Triggers a custom UI before before autofilling the screen with any data set in this @@ -506,6 +514,21 @@ public final class FillResponse implements Parcelable { } /** + * Sets a specific {@link UserData} for field classification for this request only. + * + * @return this builder + * @throws IllegalStateException if the FillResponse + * {@link #setAuthentication(AutofillId[], IntentSender, RemoteViews) + * requires authentication}. + */ + public Builder setUserData(@NonNull UserData userData) { + throwIfDestroyed(); + throwIfAuthenticationCalled(); + mUserData = Preconditions.checkNotNull(userData); + return this; + } + + /** * Builds a new {@link FillResponse} instance. * * @throws IllegalStateException if any of the following conditions occur: @@ -599,6 +622,9 @@ public final class FillResponse implements Parcelable { if (mFieldClassificationIds != null) { builder.append(Arrays.toString(mFieldClassificationIds)); } + if (mUserData != null) { + builder.append(", userData=").append(mUserData); + } return builder.append("]").toString(); } @@ -621,6 +647,7 @@ public final class FillResponse implements Parcelable { parcel.writeParcelable(mPresentation, flags); parcel.writeParcelable(mHeader, flags); parcel.writeParcelable(mFooter, flags); + parcel.writeParcelable(mUserData, flags); parcel.writeParcelableArray(mIgnoredIds, flags); parcel.writeLong(mDisableDuration); parcel.writeParcelableArray(mFieldClassificationIds, flags); @@ -661,6 +688,10 @@ public final class FillResponse implements Parcelable { if (footer != null) { builder.setFooter(footer); } + final UserData userData = parcel.readParcelable(null); + if (userData != null) { + builder.setUserData(userData); + } builder.setIgnoredIds(parcel.readParcelableArray(null, AutofillId.class)); final long disableDuration = parcel.readLong(); diff --git a/core/java/android/view/textclassifier/ConversationActions.java b/core/java/android/view/textclassifier/ConversationActions.java index 1a7b91127a7b..04b94b0e03ad 100644 --- a/core/java/android/view/textclassifier/ConversationActions.java +++ b/core/java/android/view/textclassifier/ConversationActions.java @@ -30,6 +30,7 @@ import android.os.Parcelable; import android.text.SpannedString; import android.util.ArraySet; +import com.android.internal.annotations.VisibleForTesting; import com.android.internal.util.Preconditions; import java.lang.annotation.Retention; @@ -654,6 +655,8 @@ public final class ConversationActions implements Parcelable { @NonNull @Hint private final List<String> mHints; + @Nullable + private String mCallingPackageName; private Request( @NonNull List<Message> conversation, @@ -666,15 +669,26 @@ public final class ConversationActions implements Parcelable { mHints = hints; } - private Request(Parcel in) { + private static Request readFromParcel(Parcel in) { List<Message> conversation = new ArrayList<>(); in.readParcelableList(conversation, null); - mConversation = Collections.unmodifiableList(conversation); - mTypeConfig = in.readParcelable(null); - mMaxSuggestions = in.readInt(); + + TypeConfig typeConfig = in.readParcelable(null); + + int maxSuggestions = in.readInt(); + List<String> hints = new ArrayList<>(); in.readStringList(hints); - mHints = Collections.unmodifiableList(hints); + + String callingPackageName = in.readString(); + + Request request = new Request( + conversation, + typeConfig, + maxSuggestions, + hints); + request.setCallingPackageName(callingPackageName); + return request; } @Override @@ -683,6 +697,7 @@ public final class ConversationActions implements Parcelable { parcel.writeParcelable(mTypeConfig, flags); parcel.writeInt(mMaxSuggestions); parcel.writeStringList(mHints); + parcel.writeString(mCallingPackageName); } @Override @@ -694,7 +709,7 @@ public final class ConversationActions implements Parcelable { new Creator<Request>() { @Override public Request createFromParcel(Parcel in) { - return new Request(in); + return readFromParcel(in); } @Override @@ -730,6 +745,26 @@ public final class ConversationActions implements Parcelable { return mHints; } + /** + * Sets the name of the package that is sending this request. + * <p> + * Package-private for SystemTextClassifier's use. + * @hide + */ + @VisibleForTesting(visibility = VisibleForTesting.Visibility.PACKAGE) + public void setCallingPackageName(@Nullable String callingPackageName) { + mCallingPackageName = callingPackageName; + } + + /** + * Returns the name of the package that sent this request. + * This returns {@code null} if no calling package name is set. + */ + @Nullable + public String getCallingPackageName() { + return mCallingPackageName; + } + /** Builder object to construct the {@link Request} object. */ public static final class Builder { @NonNull diff --git a/core/java/android/view/textclassifier/SystemTextClassifier.java b/core/java/android/view/textclassifier/SystemTextClassifier.java index f8fce62c84d2..c24489c8740b 100644 --- a/core/java/android/view/textclassifier/SystemTextClassifier.java +++ b/core/java/android/view/textclassifier/SystemTextClassifier.java @@ -60,7 +60,7 @@ public final class SystemTextClassifier implements TextClassifier { mSettings = Preconditions.checkNotNull(settings); mFallback = context.getSystemService(TextClassificationManager.class) .getTextClassifier(TextClassifier.LOCAL); - mPackageName = Preconditions.checkNotNull(context.getPackageName()); + mPackageName = Preconditions.checkNotNull(context.getOpPackageName()); } /** @@ -72,6 +72,7 @@ public final class SystemTextClassifier implements TextClassifier { Preconditions.checkNotNull(request); Utils.checkMainThread(); try { + request.setCallingPackageName(mPackageName); final TextSelectionCallback callback = new TextSelectionCallback(); mManagerService.onSuggestSelection(mSessionId, request, callback); final TextSelection selection = callback.mReceiver.get(); @@ -93,6 +94,7 @@ public final class SystemTextClassifier implements TextClassifier { Preconditions.checkNotNull(request); Utils.checkMainThread(); try { + request.setCallingPackageName(mPackageName); final TextClassificationCallback callback = new TextClassificationCallback(); mManagerService.onClassifyText(mSessionId, request, callback); final TextClassification classification = callback.mReceiver.get(); @@ -150,6 +152,7 @@ public final class SystemTextClassifier implements TextClassifier { Utils.checkMainThread(); try { + request.setCallingPackageName(mPackageName); final TextLanguageCallback callback = new TextLanguageCallback(); mManagerService.onDetectLanguage(mSessionId, request, callback); final TextLanguage textLanguage = callback.mReceiver.get(); @@ -168,6 +171,7 @@ public final class SystemTextClassifier implements TextClassifier { Utils.checkMainThread(); try { + request.setCallingPackageName(mPackageName); final ConversationActionsCallback callback = new ConversationActionsCallback(); mManagerService.onSuggestConversationActions(mSessionId, request, callback); final ConversationActions conversationActions = callback.mReceiver.get(); diff --git a/core/java/android/view/textclassifier/TextClassification.java b/core/java/android/view/textclassifier/TextClassification.java index e0910c0b37b7..d9f79655d588 100644 --- a/core/java/android/view/textclassifier/TextClassification.java +++ b/core/java/android/view/textclassifier/TextClassification.java @@ -37,11 +37,13 @@ import android.os.Bundle; import android.os.LocaleList; import android.os.Parcel; import android.os.Parcelable; +import android.text.SpannedString; import android.util.ArrayMap; import android.view.View.OnClickListener; import android.view.textclassifier.TextClassifier.EntityType; import android.view.textclassifier.TextClassifier.Utils; +import com.android.internal.annotations.VisibleForTesting; import com.android.internal.util.Preconditions; import java.lang.annotation.Retention; @@ -518,6 +520,7 @@ public final class TextClassification implements Parcelable { @Nullable private final LocaleList mDefaultLocales; @Nullable private final ZonedDateTime mReferenceTime; @NonNull private final Bundle mExtras; + @Nullable private String mCallingPackageName; private Request( CharSequence text, @@ -578,6 +581,26 @@ public final class TextClassification implements Parcelable { } /** + * Sets the name of the package that is sending this request. + * <p> + * For SystemTextClassifier's use. + * @hide + */ + @VisibleForTesting(visibility = VisibleForTesting.Visibility.PACKAGE) + public void setCallingPackageName(@Nullable String callingPackageName) { + mCallingPackageName = callingPackageName; + } + + /** + * Returns the name of the package that sent this request. + * This returns {@code null} if no calling package name is set. + */ + @Nullable + public String getCallingPackageName() { + return mCallingPackageName; + } + + /** * Returns the extended data. * * <p><b>NOTE: </b>Each call to this method returns a new bundle copy so clients should @@ -660,7 +683,8 @@ public final class TextClassification implements Parcelable { */ @NonNull public Request build() { - return new Request(mText, mStartIndex, mEndIndex, mDefaultLocales, mReferenceTime, + return new Request(new SpannedString(mText), mStartIndex, mEndIndex, + mDefaultLocales, mReferenceTime, mExtras == null ? Bundle.EMPTY : mExtras.deepCopy()); } } @@ -672,25 +696,37 @@ public final class TextClassification implements Parcelable { @Override public void writeToParcel(Parcel dest, int flags) { - dest.writeString(mText.toString()); + dest.writeCharSequence(mText); dest.writeInt(mStartIndex); dest.writeInt(mEndIndex); - dest.writeInt(mDefaultLocales != null ? 1 : 0); - if (mDefaultLocales != null) { - mDefaultLocales.writeToParcel(dest, flags); - } - dest.writeInt(mReferenceTime != null ? 1 : 0); - if (mReferenceTime != null) { - dest.writeString(mReferenceTime.toString()); - } + dest.writeParcelable(mDefaultLocales, flags); + dest.writeString(mReferenceTime == null ? null : mReferenceTime.toString()); + dest.writeString(mCallingPackageName); dest.writeBundle(mExtras); } + private static Request readFromParcel(Parcel in) { + final CharSequence text = in.readCharSequence(); + final int startIndex = in.readInt(); + final int endIndex = in.readInt(); + final LocaleList defaultLocales = in.readParcelable(null); + final String referenceTimeString = in.readString(); + final ZonedDateTime referenceTime = referenceTimeString == null + ? null : ZonedDateTime.parse(referenceTimeString); + final String callingPackageName = in.readString(); + final Bundle extras = in.readBundle(); + + final Request request = new Request(text, startIndex, endIndex, + defaultLocales, referenceTime, extras); + request.setCallingPackageName(callingPackageName); + return request; + } + public static final Parcelable.Creator<Request> CREATOR = new Parcelable.Creator<Request>() { @Override public Request createFromParcel(Parcel in) { - return new Request(in); + return readFromParcel(in); } @Override @@ -698,15 +734,6 @@ public final class TextClassification implements Parcelable { return new Request[size]; } }; - - private Request(Parcel in) { - mText = in.readString(); - mStartIndex = in.readInt(); - mEndIndex = in.readInt(); - mDefaultLocales = in.readInt() == 0 ? null : LocaleList.CREATOR.createFromParcel(in); - mReferenceTime = in.readInt() == 0 ? null : ZonedDateTime.parse(in.readString()); - mExtras = in.readBundle(); - } } @Override diff --git a/core/java/android/view/textclassifier/TextLanguage.java b/core/java/android/view/textclassifier/TextLanguage.java index d28459e733f0..b1609fcfe56a 100644 --- a/core/java/android/view/textclassifier/TextLanguage.java +++ b/core/java/android/view/textclassifier/TextLanguage.java @@ -26,6 +26,7 @@ import android.os.Parcel; import android.os.Parcelable; import android.util.ArrayMap; +import com.android.internal.annotations.VisibleForTesting; import com.android.internal.util.Preconditions; import java.util.Locale; @@ -90,7 +91,7 @@ public final class TextLanguage implements Parcelable { * confidence to low confidence. * * @throws IndexOutOfBoundsException if the specified index is out of range. - * @see #getLocaleCount() for the number of locales available. + * @see #getLocaleHypothesisCount() for the number of locales available. */ @NonNull public ULocale getLocale(int index) { @@ -222,11 +223,12 @@ public final class TextLanguage implements Parcelable { }; private final CharSequence mText; - private final Bundle mBundle; + private final Bundle mExtra; + @Nullable private String mCallingPackageName; private Request(CharSequence text, Bundle bundle) { mText = text; - mBundle = bundle; + mExtra = bundle; } /** @@ -238,6 +240,25 @@ public final class TextLanguage implements Parcelable { } /** + * Sets the name of the package that is sending this request. + * Package-private for SystemTextClassifier's use. + * @hide + */ + @VisibleForTesting(visibility = VisibleForTesting.Visibility.PACKAGE) + public void setCallingPackageName(@Nullable String callingPackageName) { + mCallingPackageName = callingPackageName; + } + + /** + * Returns the name of the package that sent this request. + * This returns null if no calling package name is set. + */ + @Nullable + public String getCallingPackageName() { + return mCallingPackageName; + } + + /** * Returns a bundle containing non-structured extra information about this request. * * <p><b>NOTE: </b>Each call to this method returns a new bundle copy so clients should @@ -246,7 +267,7 @@ public final class TextLanguage implements Parcelable { */ @NonNull public Bundle getExtras() { - return mBundle.deepCopy(); + return mExtra.deepCopy(); } @Override @@ -257,13 +278,18 @@ public final class TextLanguage implements Parcelable { @Override public void writeToParcel(Parcel dest, int flags) { dest.writeCharSequence(mText); - dest.writeBundle(mBundle); + dest.writeString(mCallingPackageName); + dest.writeBundle(mExtra); } private static Request readFromParcel(Parcel in) { - return new Request( - in.readCharSequence(), - in.readBundle()); + final CharSequence text = in.readCharSequence(); + final String callingPackageName = in.readString(); + final Bundle extra = in.readBundle(); + + final Request request = new Request(text, extra); + request.setCallingPackageName(callingPackageName); + return request; } /** diff --git a/core/java/android/view/textclassifier/TextLinks.java b/core/java/android/view/textclassifier/TextLinks.java index 1e42c414a365..ab341782ac58 100644 --- a/core/java/android/view/textclassifier/TextLinks.java +++ b/core/java/android/view/textclassifier/TextLinks.java @@ -30,6 +30,7 @@ import android.text.method.MovementMethod; import android.text.style.ClickableSpan; import android.text.style.URLSpan; import android.view.View; +import android.view.textclassifier.TextClassifier.EntityConfig; import android.view.textclassifier.TextClassifier.EntityType; import android.widget.TextView; @@ -205,27 +206,32 @@ public final class TextLinks implements Parcelable { private final EntityConfidence mEntityScores; private final int mStart; private final int mEnd; - @Nullable final URLSpan mUrlSpan; + private final Bundle mExtras; + @Nullable private final URLSpan mUrlSpan; /** * Create a new TextLink. * * @param start The start index of the identified subsequence * @param end The end index of the identified subsequence - * @param entityScores A mapping of entity type to confidence score + * @param entityConfidence A mapping of entity type to confidence score + * @param extras A bundle containing custom data related to this TextLink * @param urlSpan An optional URLSpan to delegate to. NOTE: Not parcelled * - * @throws IllegalArgumentException if entityScores is null or empty + * @throws IllegalArgumentException if {@code entityConfidence} is null or empty + * @throws IllegalArgumentException if {@code start} is greater than {@code end} */ - TextLink(int start, int end, Map<String, Float> entityScores, - @Nullable URLSpan urlSpan) { - Preconditions.checkNotNull(entityScores); - Preconditions.checkArgument(!entityScores.isEmpty()); + private TextLink(int start, int end, @NonNull EntityConfidence entityConfidence, + @NonNull Bundle extras, @Nullable URLSpan urlSpan) { + Preconditions.checkNotNull(entityConfidence); + Preconditions.checkArgument(!entityConfidence.getEntities().isEmpty()); Preconditions.checkArgument(start <= end); + Preconditions.checkNotNull(extras); mStart = start; mEnd = end; - mEntityScores = new EntityConfidence(entityScores); + mEntityScores = entityConfidence; mUrlSpan = urlSpan; + mExtras = extras; } /** @@ -274,6 +280,13 @@ public final class TextLinks implements Parcelable { return mEntityScores.getConfidenceScore(entityType); } + /** + * Returns a bundle containing custom data related to this TextLink. + */ + public Bundle getExtras() { + return mExtras; + } + @Override public String toString() { return String.format(Locale.US, @@ -291,13 +304,22 @@ public final class TextLinks implements Parcelable { mEntityScores.writeToParcel(dest, flags); dest.writeInt(mStart); dest.writeInt(mEnd); + dest.writeBundle(mExtras); + } + + private static TextLink readFromParcel(Parcel in) { + final EntityConfidence entityConfidence = EntityConfidence.CREATOR.createFromParcel(in); + final int start = in.readInt(); + final int end = in.readInt(); + final Bundle extras = in.readBundle(); + return new TextLink(start, end, entityConfidence, extras, null /* urlSpan */); } public static final Parcelable.Creator<TextLink> CREATOR = new Parcelable.Creator<TextLink>() { @Override public TextLink createFromParcel(Parcel in) { - return new TextLink(in); + return readFromParcel(in); } @Override @@ -305,13 +327,6 @@ public final class TextLinks implements Parcelable { return new TextLink[size]; } }; - - private TextLink(Parcel in) { - mEntityScores = EntityConfidence.CREATOR.createFromParcel(in); - mStart = in.readInt(); - mEnd = in.readInt(); - mUrlSpan = null; - } } /** @@ -321,23 +336,21 @@ public final class TextLinks implements Parcelable { private final CharSequence mText; @Nullable private final LocaleList mDefaultLocales; - @Nullable private final TextClassifier.EntityConfig mEntityConfig; + @Nullable private final EntityConfig mEntityConfig; private final boolean mLegacyFallback; - private String mCallingPackageName; + @Nullable private String mCallingPackageName; private final Bundle mExtras; private Request( CharSequence text, LocaleList defaultLocales, - TextClassifier.EntityConfig entityConfig, + EntityConfig entityConfig, boolean legacyFallback, - String callingPackageName, Bundle extras) { mText = text; mDefaultLocales = defaultLocales; mEntityConfig = entityConfig; mLegacyFallback = legacyFallback; - mCallingPackageName = callingPackageName; mExtras = extras; } @@ -360,10 +373,10 @@ public final class TextLinks implements Parcelable { /** * @return The config representing the set of entities to look for - * @see Builder#setEntityConfig(TextClassifier.EntityConfig) + * @see Builder#setEntityConfig(EntityConfig) */ @Nullable - public TextClassifier.EntityConfig getEntityConfig() { + public EntityConfig getEntityConfig() { return mEntityConfig; } @@ -378,13 +391,26 @@ public final class TextLinks implements Parcelable { } /** - * Sets the name of the package that requested the links to get generated. + * Sets the name of the package that is sending this request. + * <p> + * Package-private for SystemTextClassifier's use. + * @hide */ - void setCallingPackageName(@Nullable String callingPackageName) { + @VisibleForTesting(visibility = VisibleForTesting.Visibility.PACKAGE) + public void setCallingPackageName(@Nullable String callingPackageName) { mCallingPackageName = callingPackageName; } /** + * Returns the name of the package that sent this request. + * This returns {@code null} if no calling package name is set. + */ + @Nullable + public String getCallingPackageName() { + return mCallingPackageName; + } + + /** * Returns the extended data. * * <p><b>NOTE: </b>Each call to this method returns a new bundle copy so clients should @@ -404,9 +430,8 @@ public final class TextLinks implements Parcelable { private final CharSequence mText; @Nullable private LocaleList mDefaultLocales; - @Nullable private TextClassifier.EntityConfig mEntityConfig; + @Nullable private EntityConfig mEntityConfig; private boolean mLegacyFallback = true; // Use legacy fall back by default. - private String mCallingPackageName; @Nullable private Bundle mExtras; public Builder(@NonNull CharSequence text) { @@ -434,7 +459,7 @@ public final class TextLinks implements Parcelable { * @return this builder */ @NonNull - public Builder setEntityConfig(@Nullable TextClassifier.EntityConfig entityConfig) { + public Builder setEntityConfig(@Nullable EntityConfig entityConfig) { mEntityConfig = entityConfig; return this; } @@ -455,18 +480,6 @@ public final class TextLinks implements Parcelable { } /** - * Sets the name of the package that requested the links to get generated. - * - * @return this builder - * @hide - */ - @NonNull - public Builder setCallingPackageName(@Nullable String callingPackageName) { - mCallingPackageName = callingPackageName; - return this; - } - - /** * Sets the extended data. * * @return this builder @@ -483,21 +496,11 @@ public final class TextLinks implements Parcelable { public Request build() { return new Request( mText, mDefaultLocales, mEntityConfig, - mLegacyFallback, mCallingPackageName, + mLegacyFallback, mExtras == null ? Bundle.EMPTY : mExtras.deepCopy()); } } - /** - * @return the name of the package that requested the links to get generated. - * TODO: make available as system API - * @hide - */ - @Nullable - public String getCallingPackageName() { - return mCallingPackageName; - } - @Override public int describeContents() { return 0; @@ -506,23 +509,30 @@ public final class TextLinks implements Parcelable { @Override public void writeToParcel(Parcel dest, int flags) { dest.writeString(mText.toString()); - dest.writeInt(mDefaultLocales != null ? 1 : 0); - if (mDefaultLocales != null) { - mDefaultLocales.writeToParcel(dest, flags); - } - dest.writeInt(mEntityConfig != null ? 1 : 0); - if (mEntityConfig != null) { - mEntityConfig.writeToParcel(dest, flags); - } + dest.writeParcelable(mDefaultLocales, flags); + dest.writeParcelable(mEntityConfig, flags); dest.writeString(mCallingPackageName); dest.writeBundle(mExtras); } + private static Request readFromParcel(Parcel in) { + final String text = in.readString(); + final LocaleList defaultLocales = in.readParcelable(null); + final EntityConfig entityConfig = in.readParcelable(null); + final String callingPackageName = in.readString(); + final Bundle extras = in.readBundle(); + + final Request request = new Request(text, defaultLocales, entityConfig, + /* legacyFallback= */ true, extras); + request.setCallingPackageName(callingPackageName); + return request; + } + public static final Parcelable.Creator<Request> CREATOR = new Parcelable.Creator<Request>() { @Override public Request createFromParcel(Parcel in) { - return new Request(in); + return readFromParcel(in); } @Override @@ -530,16 +540,6 @@ public final class TextLinks implements Parcelable { return new Request[size]; } }; - - private Request(Parcel in) { - mText = in.readString(); - mDefaultLocales = in.readInt() == 0 ? null : LocaleList.CREATOR.createFromParcel(in); - mEntityConfig = in.readInt() == 0 - ? null : TextClassifier.EntityConfig.CREATOR.createFromParcel(in); - mLegacyFallback = true; - mCallingPackageName = in.readString(); - mExtras = in.readBundle(); - } } /** @@ -645,9 +645,20 @@ public final class TextLinks implements Parcelable { * @throws IllegalArgumentException if entityScores is null or empty. */ @NonNull - public Builder addLink(int start, int end, Map<String, Float> entityScores) { - mLinks.add(new TextLink(start, end, entityScores, null)); - return this; + public Builder addLink(int start, int end, @NonNull Map<String, Float> entityScores) { + return addLink(start, end, entityScores, Bundle.EMPTY, null); + } + + /** + * Adds a TextLink. + * + * @see #addLink(int, int, Map) + * @param extras An optional bundle containing custom data related to this TextLink + */ + @NonNull + public Builder addLink(int start, int end, @NonNull Map<String, Float> entityScores, + @NonNull Bundle extras) { + return addLink(start, end, entityScores, extras, null); } /** @@ -655,9 +666,15 @@ public final class TextLinks implements Parcelable { * @param urlSpan An optional URLSpan to delegate to. NOTE: Not parcelled. */ @NonNull - Builder addLink(int start, int end, Map<String, Float> entityScores, + Builder addLink(int start, int end, @NonNull Map<String, Float> entityScores, @Nullable URLSpan urlSpan) { - mLinks.add(new TextLink(start, end, entityScores, urlSpan)); + return addLink(start, end, entityScores, Bundle.EMPTY, urlSpan); + } + + private Builder addLink(int start, int end, @NonNull Map<String, Float> entityScores, + @NonNull Bundle extras, @Nullable URLSpan urlSpan) { + mLinks.add(new TextLink( + start, end, new EntityConfidence(entityScores), extras, urlSpan)); return this; } diff --git a/core/java/android/view/textclassifier/TextSelection.java b/core/java/android/view/textclassifier/TextSelection.java index f23691586a2a..4a6f3e53b223 100644 --- a/core/java/android/view/textclassifier/TextSelection.java +++ b/core/java/android/view/textclassifier/TextSelection.java @@ -24,10 +24,12 @@ import android.os.Bundle; import android.os.LocaleList; import android.os.Parcel; import android.os.Parcelable; +import android.text.SpannedString; import android.util.ArrayMap; import android.view.textclassifier.TextClassifier.EntityType; import android.view.textclassifier.TextClassifier.Utils; +import com.android.internal.annotations.VisibleForTesting; import com.android.internal.util.Preconditions; import java.util.Locale; @@ -209,6 +211,7 @@ public final class TextSelection implements Parcelable { @Nullable private final LocaleList mDefaultLocales; private final boolean mDarkLaunchAllowed; private final Bundle mExtras; + @Nullable private String mCallingPackageName; private Request( CharSequence text, @@ -270,6 +273,26 @@ public final class TextSelection implements Parcelable { } /** + * Sets the name of the package that is sending this request. + * <p> + * Package-private for SystemTextClassifier's use. + * @hide + */ + @VisibleForTesting(visibility = VisibleForTesting.Visibility.PACKAGE) + public void setCallingPackageName(@Nullable String callingPackageName) { + mCallingPackageName = callingPackageName; + } + + /** + * Returns the name of the package that sent this request. + * This returns {@code null} if no calling package name is set. + */ + @Nullable + public String getCallingPackageName() { + return mCallingPackageName; + } + + /** * Returns the extended data. * * <p><b>NOTE: </b>Each call to this method returns a new bundle copy so clients should @@ -355,7 +378,7 @@ public final class TextSelection implements Parcelable { */ @NonNull public Request build() { - return new Request(mText, mStartIndex, mEndIndex, + return new Request(new SpannedString(mText), mStartIndex, mEndIndex, mDefaultLocales, mDarkLaunchAllowed, mExtras == null ? Bundle.EMPTY : mExtras.deepCopy()); } @@ -368,21 +391,33 @@ public final class TextSelection implements Parcelable { @Override public void writeToParcel(Parcel dest, int flags) { - dest.writeString(mText.toString()); + dest.writeCharSequence(mText); dest.writeInt(mStartIndex); dest.writeInt(mEndIndex); - dest.writeInt(mDefaultLocales != null ? 1 : 0); - if (mDefaultLocales != null) { - mDefaultLocales.writeToParcel(dest, flags); - } + dest.writeParcelable(mDefaultLocales, flags); + dest.writeString(mCallingPackageName); dest.writeBundle(mExtras); } + private static Request readFromParcel(Parcel in) { + final CharSequence text = in.readCharSequence(); + final int startIndex = in.readInt(); + final int endIndex = in.readInt(); + final LocaleList defaultLocales = in.readParcelable(null); + final String callingPackageName = in.readString(); + final Bundle extras = in.readBundle(); + + final Request request = new Request(text, startIndex, endIndex, defaultLocales, + /* darkLaunchAllowed= */ false, extras); + request.setCallingPackageName(callingPackageName); + return request; + } + public static final Parcelable.Creator<Request> CREATOR = new Parcelable.Creator<Request>() { @Override public Request createFromParcel(Parcel in) { - return new Request(in); + return readFromParcel(in); } @Override @@ -390,15 +425,6 @@ public final class TextSelection implements Parcelable { return new Request[size]; } }; - - private Request(Parcel in) { - mText = in.readString(); - mStartIndex = in.readInt(); - mEndIndex = in.readInt(); - mDefaultLocales = in.readInt() == 0 ? null : LocaleList.CREATOR.createFromParcel(in); - mDarkLaunchAllowed = false; - mExtras = in.readBundle(); - } } @Override diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml index 1dd42b8162b3..4dedd492fdb3 100644 --- a/core/res/AndroidManifest.xml +++ b/core/res/AndroidManifest.xml @@ -1648,7 +1648,7 @@ @hide --> <permission android:name="android.permission.SUSPEND_APPS" - android:protectionLevel="signature|privileged" /> + android:protectionLevel="signature|wellbeing" /> <!-- Allows applications to discover and pair bluetooth devices. <p>Protection level: normal @@ -4086,10 +4086,10 @@ confirmation UI for full backup/restore --> <uses-permission android:name="android.permission.CONFIRM_FULL_BACKUP"/> - <!-- Allows the holder to access and manage instant applications on the device. - @hide --> + <!-- @SystemApi Allows the holder to access and manage instant applications on the device. + @hide --> <permission android:name="android.permission.ACCESS_INSTANT_APPS" - android:protectionLevel="signature|installer|verifier" /> + android:protectionLevel="signature|installer|verifier|wellbeing" /> <uses-permission android:name="android.permission.ACCESS_INSTANT_APPS"/> <!-- Allows the holder to view the instant applications on the device. diff --git a/core/res/res/values/attrs_manifest.xml b/core/res/res/values/attrs_manifest.xml index 854582b21340..f8004ea78e6a 100644 --- a/core/res/res/values/attrs_manifest.xml +++ b/core/res/res/values/attrs_manifest.xml @@ -268,6 +268,9 @@ <!-- Additional flag from base permission type: this permission can be automatically granted to the system default text classifier --> <flag name="textClassifier" value="0x10000" /> + <!-- Additional flag from base permission type: this permission will be granted to the + wellbeing app, as defined by the OEM. --> + <flag name="wellbeing" value="0x20000" /> </attr> <!-- Flags indicating more context for a permission group. --> diff --git a/core/res/res/values/config.xml b/core/res/res/values/config.xml index 62ec5c474297..101f92b2097c 100644 --- a/core/res/res/values/config.xml +++ b/core/res/res/values/config.xml @@ -3349,6 +3349,13 @@ See android.view.textclassifier.TextClassificationManager. --> <string name="config_defaultTextClassifierPackage" translatable="false"></string> + + <!-- The package name for the default wellbeing app. + This package must be trusted, as it has the permissions to control other applications + on the device. + Example: "com.android.wellbeing" + --> + <string name="config_defaultWellbeingPackage" translatable="false"></string> <!-- The package name for the system's content capture service. This service must be trusted, as it can be activated without explicit consent of the user. diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml index 82a679e14534..b24cdba5ec47 100644 --- a/core/res/res/values/symbols.xml +++ b/core/res/res/values/symbols.xml @@ -3265,6 +3265,7 @@ <java-symbol type="string" name="notification_channel_do_not_disturb" /> <java-symbol type="string" name="config_defaultAutofillService" /> <java-symbol type="string" name="config_defaultTextClassifierPackage" /> + <java-symbol type="string" name="config_defaultWellbeingPackage" /> <java-symbol type="string" name="config_defaultContentCaptureService" /> <java-symbol type="string" name="config_defaultAugmentedAutofillService" /> diff --git a/core/tests/coretests/src/android/view/textclassifier/TextClassificationTest.java b/core/tests/coretests/src/android/view/textclassifier/TextClassificationTest.java index 91a54409608a..aaf7312fe0e6 100644 --- a/core/tests/coretests/src/android/view/textclassifier/TextClassificationTest.java +++ b/core/tests/coretests/src/android/view/textclassifier/TextClassificationTest.java @@ -189,6 +189,7 @@ public class TextClassificationTest { Instant.ofEpochMilli(946771200000L), // 2000-01-02 ZoneId.of("UTC")); final String text = "text"; + final String packageName = "packageName"; final TextClassification.Request reference = new TextClassification.Request.Builder(text, 0, text.length()) @@ -196,6 +197,7 @@ public class TextClassificationTest { .setReferenceTime(referenceTime) .setExtras(BUNDLE) .build(); + reference.setCallingPackageName(packageName); // Parcel and unparcel. final Parcel parcel = Parcel.obtain(); @@ -204,12 +206,13 @@ public class TextClassificationTest { final TextClassification.Request result = TextClassification.Request.CREATOR.createFromParcel(parcel); - assertEquals(text, result.getText()); + assertEquals(text, result.getText().toString()); assertEquals(0, result.getStartIndex()); assertEquals(text.length(), result.getEndIndex()); assertEquals(referenceTime, result.getReferenceTime()); assertEquals("en-US,de-DE", result.getDefaultLocales().toLanguageTags()); assertEquals(referenceTime, result.getReferenceTime()); assertEquals(BUNDLE_VALUE, result.getExtras().getString(BUNDLE_KEY)); + assertEquals(packageName, result.getCallingPackageName()); } } diff --git a/core/tests/coretests/src/android/view/textclassifier/TextLanguageTest.java b/core/tests/coretests/src/android/view/textclassifier/TextLanguageTest.java index 75ca769294ce..1dcaed6f6a1e 100644 --- a/core/tests/coretests/src/android/view/textclassifier/TextLanguageTest.java +++ b/core/tests/coretests/src/android/view/textclassifier/TextLanguageTest.java @@ -69,10 +69,12 @@ public final class TextLanguageTest { final String bundleKey = "experiment.str"; final Bundle bundle = new Bundle(); bundle.putString(bundleKey, "bundle"); + final String packageName = "packageName"; final TextLanguage.Request reference = new TextLanguage.Request.Builder(text) .setExtras(bundle) .build(); + reference.setCallingPackageName(packageName); final Parcel parcel = Parcel.obtain(); reference.writeToParcel(parcel, 0); @@ -81,5 +83,6 @@ public final class TextLanguageTest { assertEquals(text, result.getText()); assertEquals("bundle", result.getExtras().getString(bundleKey)); + assertEquals(packageName, result.getCallingPackageName()); } } diff --git a/core/tests/coretests/src/android/view/textclassifier/TextLinksTest.java b/core/tests/coretests/src/android/view/textclassifier/TextLinksTest.java index f6ec0e6480f2..f022d040246b 100644 --- a/core/tests/coretests/src/android/view/textclassifier/TextLinksTest.java +++ b/core/tests/coretests/src/android/view/textclassifier/TextLinksTest.java @@ -64,7 +64,7 @@ public class TextLinksTest { public void testParcel() { final String fullText = "this is just a test"; final TextLinks reference = new TextLinks.Builder(fullText) - .addLink(0, 4, getEntityScores(0.f, 0.f, 1.f)) + .addLink(0, 4, getEntityScores(0.f, 0.f, 1.f), BUNDLE) .addLink(5, 12, getEntityScores(.8f, .1f, .5f)) .setExtras(BUNDLE) .build(); @@ -82,6 +82,7 @@ public class TextLinksTest { assertEquals(1, resultList.get(0).getEntityCount()); assertEquals(TextClassifier.TYPE_OTHER, resultList.get(0).getEntity(0)); assertEquals(1.f, resultList.get(0).getConfidenceScore(TextClassifier.TYPE_OTHER), 1e-7f); + assertEquals(BUNDLE_VALUE, resultList.get(0).getExtras().getString(BUNDLE_KEY)); assertEquals(5, resultList.get(1).getStart()); assertEquals(12, resultList.get(1).getEnd()); assertEquals(3, resultList.get(1).getEntityCount()); @@ -96,6 +97,7 @@ public class TextLinksTest { @Test public void testParcelOptions() { + final String packageName = "packageName"; final TextClassifier.EntityConfig entityConfig = TextClassifier.EntityConfig.create( Arrays.asList(TextClassifier.HINT_TEXT_IS_EDITABLE), Arrays.asList("a", "b", "c"), @@ -105,6 +107,7 @@ public class TextLinksTest { .setEntityConfig(entityConfig) .setExtras(BUNDLE) .build(); + reference.setCallingPackageName(packageName); // Parcel and unparcel. final Parcel parcel = Parcel.obtain(); @@ -119,5 +122,6 @@ public class TextLinksTest { assertEquals(new HashSet<String>(Arrays.asList("a", "c")), result.getEntityConfig().resolveEntityListModifications(Collections.emptyList())); assertEquals(BUNDLE_VALUE, result.getExtras().getString(BUNDLE_KEY)); + assertEquals(packageName, result.getCallingPackageName()); } } diff --git a/core/tests/coretests/src/android/view/textclassifier/TextSelectionTest.java b/core/tests/coretests/src/android/view/textclassifier/TextSelectionTest.java index 7ea5108bc3bb..2ea49f7d21be 100644 --- a/core/tests/coretests/src/android/view/textclassifier/TextSelectionTest.java +++ b/core/tests/coretests/src/android/view/textclassifier/TextSelectionTest.java @@ -75,11 +75,13 @@ public class TextSelectionTest { @Test public void testParcelRequest() { final String text = "text"; + final String packageName = "packageName"; final TextSelection.Request reference = new TextSelection.Request.Builder(text, 0, text.length()) .setDefaultLocales(new LocaleList(Locale.US, Locale.GERMANY)) .setExtras(BUNDLE) .build(); + reference.setCallingPackageName(packageName); // Parcel and unparcel. final Parcel parcel = Parcel.obtain(); @@ -87,10 +89,11 @@ public class TextSelectionTest { parcel.setDataPosition(0); final TextSelection.Request result = TextSelection.Request.CREATOR.createFromParcel(parcel); - assertEquals(text, result.getText()); + assertEquals(text, result.getText().toString()); assertEquals(0, result.getStartIndex()); assertEquals(text.length(), result.getEndIndex()); assertEquals("en-US,de-DE", result.getDefaultLocales().toLanguageTags()); assertEquals(BUNDLE_VALUE, result.getExtras().getString(BUNDLE_KEY)); + assertEquals(packageName, result.getCallingPackageName()); } } diff --git a/location/java/android/location/ILocationManager.aidl b/location/java/android/location/ILocationManager.aidl index ae87998a1615..32c752064a69 100644 --- a/location/java/android/location/ILocationManager.aidl +++ b/location/java/android/location/ILocationManager.aidl @@ -96,9 +96,7 @@ interface ILocationManager void addTestProvider(String name, in ProviderProperties properties, String opPackageName); void removeTestProvider(String provider, String opPackageName); void setTestProviderLocation(String provider, in Location loc, String opPackageName); - void clearTestProviderLocation(String provider, String opPackageName); void setTestProviderEnabled(String provider, boolean enabled, String opPackageName); - void clearTestProviderEnabled(String provider, String opPackageName); // --- deprecated --- void setTestProviderStatus(String provider, int status, in Bundle extras, long updateTime, @@ -108,12 +106,8 @@ interface ILocationManager // --- internal --- - // Used by location providers to tell the location manager when it has a new location. - // Passive is true if the location is coming from the passive provider, in which case - // it need not be shared with other providers. + // --- deprecated --- void reportLocation(in Location location, boolean passive); - - // Used when a (initially Gnss) Location batch arrives void reportLocationBatch(in List<Location> locations); // for reporting callback completion diff --git a/location/java/android/location/LocationManager.java b/location/java/android/location/LocationManager.java index 3bf98b352b40..334170e5ce03 100644 --- a/location/java/android/location/LocationManager.java +++ b/location/java/android/location/LocationManager.java @@ -1537,14 +1537,11 @@ public class LocationManager { * mock location app op} is not set to {@link android.app.AppOpsManager#MODE_ALLOWED * allowed} for your app. * @throws IllegalArgumentException if no provider with the given name exists + * + * @deprecated This function has always been a no-op, and may be removed in the future. */ - public void clearTestProviderLocation(String provider) { - try { - mService.clearTestProviderLocation(provider, mContext.getOpPackageName()); - } catch (RemoteException e) { - throw e.rethrowFromSystemServer(); - } - } + @Deprecated + public void clearTestProviderLocation(String provider) {} /** * Sets a mock enabled value for the given provider. This value will be used in place @@ -1575,13 +1572,12 @@ public class LocationManager { * mock location app op} is not set to {@link android.app.AppOpsManager#MODE_ALLOWED * allowed} for your app. * @throws IllegalArgumentException if no provider with the given name exists + * + * @deprecated Use {@link #setTestProviderEnabled(String, boolean)} instead. */ + @Deprecated public void clearTestProviderEnabled(String provider) { - try { - mService.clearTestProviderEnabled(provider, mContext.getOpPackageName()); - } catch (RemoteException e) { - throw e.rethrowFromSystemServer(); - } + setTestProviderEnabled(provider, true); } /** diff --git a/location/java/com/android/internal/location/ILocationProvider.aidl b/location/java/com/android/internal/location/ILocationProvider.aidl index 39c2d92bf278..71b54fb65ae5 100644 --- a/location/java/com/android/internal/location/ILocationProvider.aidl +++ b/location/java/com/android/internal/location/ILocationProvider.aidl @@ -16,29 +16,26 @@ package com.android.internal.location; -import android.location.Location; -import android.net.NetworkInfo; import android.os.Bundle; import android.os.WorkSource; -import com.android.internal.location.ProviderProperties; +import com.android.internal.location.ILocationProviderManager; import com.android.internal.location.ProviderRequest; /** - * Binder interface for services that implement location providers. - * <p>Use {@link LocationProviderBase} as a helper to implement this - * interface. + * Binder interface for services that implement location providers. Do not implement this directly, + * extend {@link LocationProviderBase} instead. * @hide */ interface ILocationProvider { - void enable(); - void disable(); - void setRequest(in ProviderRequest request, in WorkSource ws); + oneway void setLocationProviderManager(in ILocationProviderManager manager); - // --- deprecated (but still supported) --- - ProviderProperties getProperties(); + oneway void setRequest(in ProviderRequest request, in WorkSource ws); + + oneway void sendExtraCommand(String command, in Bundle extras); + + // --- deprecated and will be removed the future --- int getStatus(out Bundle extras); long getStatusUpdateTime(); - boolean sendExtraCommand(String command, inout Bundle extras); } diff --git a/location/java/com/android/internal/location/ILocationProviderManager.aidl b/location/java/com/android/internal/location/ILocationProviderManager.aidl new file mode 100644 index 000000000000..b1b8f0c7c3f7 --- /dev/null +++ b/location/java/com/android/internal/location/ILocationProviderManager.aidl @@ -0,0 +1,34 @@ +/* + * Copyright (C) 2009 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; + +import android.location.Location; + +import com.android.internal.location.ProviderProperties; + +/** + * Binder interface for manager of all location providers. + * @hide + */ +interface ILocationProviderManager { + + void onSetEnabled(boolean enabled); + + void onSetProperties(in ProviderProperties properties); + + void onReportLocation(in Location location); +} diff --git a/location/java/com/android/internal/location/ProviderRequest.java b/location/java/com/android/internal/location/ProviderRequest.java index 88919f628638..a45c20d9d09d 100644 --- a/location/java/com/android/internal/location/ProviderRequest.java +++ b/location/java/com/android/internal/location/ProviderRequest.java @@ -16,15 +16,15 @@ package com.android.internal.location; -import java.util.ArrayList; -import java.util.List; - import android.annotation.UnsupportedAppUsage; import android.location.LocationRequest; import android.os.Parcel; import android.os.Parcelable; import android.util.TimeUtils; +import java.util.ArrayList; +import java.util.List; + /** @hide */ public final class ProviderRequest implements Parcelable { /** Location reporting is requested (true) */ @@ -36,6 +36,13 @@ public final class ProviderRequest implements Parcelable { public long interval = Long.MAX_VALUE; /** + * When this flag is true, providers should ignore all location settings, user consents, power + * restrictions or any other restricting factors and always satisfy this request to the best of + * their ability. This flag should only be used in event of an emergency. + */ + public boolean forceLocation = false; + + /** * Whether provider shall make stronger than normal tradeoffs to substantially restrict power * use. */ diff --git a/location/lib/api/current.txt b/location/lib/api/current.txt index d19559e8cccd..10c344775019 100644 --- a/location/lib/api/current.txt +++ b/location/lib/api/current.txt @@ -8,14 +8,18 @@ package com.android.location.provider { public abstract class LocationProviderBase { ctor public LocationProviderBase(java.lang.String, com.android.location.provider.ProviderPropertiesUnbundled); method public android.os.IBinder getBinder(); - method public abstract void onDisable(); - method public void onDump(java.io.FileDescriptor, java.io.PrintWriter, java.lang.String[]); - method public abstract void onEnable(); - method public deprecated int onGetStatus(android.os.Bundle); - method public deprecated long onGetStatusUpdateTime(); - method public boolean onSendExtraCommand(java.lang.String, android.os.Bundle); - method public abstract void onSetRequest(com.android.location.provider.ProviderRequestUnbundled, android.os.WorkSource); - method public final void reportLocation(android.location.Location); + method public boolean isEnabled(); + method protected deprecated void onDisable(); + method protected void onDump(java.io.FileDescriptor, java.io.PrintWriter, java.lang.String[]); + method protected deprecated void onEnable(); + method protected deprecated int onGetStatus(android.os.Bundle); + method protected deprecated long onGetStatusUpdateTime(); + method protected void onInit(); + method protected boolean onSendExtraCommand(java.lang.String, android.os.Bundle); + method protected abstract void onSetRequest(com.android.location.provider.ProviderRequestUnbundled, android.os.WorkSource); + method public void reportLocation(android.location.Location); + method public void setEnabled(boolean); + method public void setProperties(com.android.location.provider.ProviderPropertiesUnbundled); field public static final java.lang.String EXTRA_NO_GPS_LOCATION = "noGPSLocation"; field public static final java.lang.String FUSED_PROVIDER = "fused"; } @@ -38,6 +42,7 @@ package com.android.location.provider { } public final class ProviderRequestUnbundled { + method public boolean getForceLocation(); method public long getInterval(); method public java.util.List<com.android.location.provider.LocationRequestUnbundled> getLocationRequests(); method public boolean getReportLocation(); diff --git a/location/lib/java/com/android/location/provider/LocationProviderBase.java b/location/lib/java/com/android/location/provider/LocationProviderBase.java index d45a4bac8f96..5bcec92c4fba 100644 --- a/location/lib/java/com/android/location/provider/LocationProviderBase.java +++ b/location/lib/java/com/android/location/provider/LocationProviderBase.java @@ -16,6 +16,7 @@ package com.android.location.provider; +import android.annotation.Nullable; import android.content.Context; import android.location.ILocationManager; import android.location.Location; @@ -29,12 +30,11 @@ import android.os.WorkSource; import android.util.Log; import com.android.internal.location.ILocationProvider; +import com.android.internal.location.ILocationProviderManager; import com.android.internal.location.ProviderProperties; import com.android.internal.location.ProviderRequest; -import com.android.internal.util.FastPrintWriter; import java.io.FileDescriptor; -import java.io.FileOutputStream; import java.io.PrintWriter; /** @@ -55,12 +55,6 @@ import java.io.PrintWriter; * of this package for more information. */ public abstract class LocationProviderBase { - private final String TAG; - - /** @hide */ - protected final ILocationManager mLocationManager; - private final ProviderProperties mProperties; - private final IBinder mBinder; /** * Bundle key for a version of the location containing no GPS data. @@ -77,49 +71,34 @@ public abstract class LocationProviderBase { */ public static final String FUSED_PROVIDER = LocationManager.FUSED_PROVIDER; - private final class Service extends ILocationProvider.Stub { - @Override - public void enable() { - onEnable(); - } - @Override - public void disable() { - onDisable(); - } - @Override - public void setRequest(ProviderRequest request, WorkSource ws) { - onSetRequest(new ProviderRequestUnbundled(request), ws); - } - @Override - public ProviderProperties getProperties() { - return mProperties; - } - @Override - public int getStatus(Bundle extras) { - return onGetStatus(extras); - } - @Override - public long getStatusUpdateTime() { - return onGetStatusUpdateTime(); - } - @Override - public boolean sendExtraCommand(String command, Bundle extras) { - return onSendExtraCommand(command, extras); - } - @Override - public void dump(FileDescriptor fd, String[] args) { - PrintWriter pw = new FastPrintWriter(new FileOutputStream(fd)); - onDump(fd, pw, args); - pw.flush(); - } - } + private final String mTag; + private final IBinder mBinder; + + /** + * This field may be removed in the future, do not rely on it. + * + * @deprecated Do not use this field! Use LocationManager APIs instead. If you use this field + * you may be broken in the future. + * @hide + */ + @Deprecated + protected final ILocationManager mLocationManager; + + // write locked on mBinder, read lock is optional depending on atomicity requirements + @Nullable private volatile ILocationProviderManager mManager; + private volatile ProviderProperties mProperties; + private volatile boolean mEnabled; public LocationProviderBase(String tag, ProviderPropertiesUnbundled properties) { - TAG = tag; - IBinder b = ServiceManager.getService(Context.LOCATION_SERVICE); - mLocationManager = ILocationManager.Stub.asInterface(b); - mProperties = properties.getProviderProperties(); + mTag = tag; mBinder = new Service(); + + mLocationManager = ILocationManager.Stub.asInterface( + ServiceManager.getService(Context.LOCATION_SERVICE)); + + mManager = null; + mProperties = properties.getProviderProperties(); + mEnabled = true; } public IBinder getBinder() { @@ -127,51 +106,116 @@ public abstract class LocationProviderBase { } /** - * Used by the location provider to report new locations. + * Sets whether this provider is currently enabled or not. Note that this is specific to the + * provider only, and is not related to global location settings. This is a hint to the Location + * Manager that this provider will generally be unable to fulfill incoming requests. This + * provider may still receive callbacks to onSetRequest while not enabled, and must decide + * whether to attempt to satisfy those requests or not. * - * @param location new Location to report - * - * Requires the android.permission.INSTALL_LOCATION_PROVIDER permission. + * Some guidelines: providers should set their own enabled/disabled status based only on state + * "owned" by that provider. For instance, providers should not take into account the state of + * the location master setting when setting themselves enabled or disabled, as this state is not + * owned by a particular provider. If a provider requires some additional user consent that is + * particular to the provider, this should be use to set the enabled/disabled state. If the + * provider proxies to another provider, the child provider's enabled/disabled state should be + * taken into account in the parent's enabled/disabled state. For most providers, it is expected + * that they will be always enabled. */ - public final void reportLocation(Location location) { - try { - mLocationManager.reportLocation(location, false); - } catch (RemoteException e) { - Log.e(TAG, "RemoteException", e); - } catch (Exception e) { - // never crash provider, might be running in a system process - Log.e(TAG, "Exception", e); + public void setEnabled(boolean enabled) { + synchronized (mBinder) { + if (mEnabled == enabled) { + return; + } + + mEnabled = enabled; + } + + ILocationProviderManager manager = mManager; + if (manager != null) { + try { + manager.onSetEnabled(mEnabled); + } catch (RemoteException | RuntimeException e) { + Log.w(mTag, e); + } } } /** - * Enable the location provider. - * <p>The provider may initialize resources, but does - * not yet need to report locations. + * Sets the provider properties that may be queried by clients. Generally speaking, providers + * should try to avoid changing their properties after construction. */ - public abstract void onEnable(); + public void setProperties(ProviderPropertiesUnbundled properties) { + synchronized (mBinder) { + mProperties = properties.getProviderProperties(); + } + + ILocationProviderManager manager = mManager; + if (manager != null) { + try { + manager.onSetProperties(mProperties); + } catch (RemoteException | RuntimeException e) { + Log.w(mTag, e); + } + } + } /** - * Disable the location provider. - * <p>The provider must release resources, and stop - * performing work. It may no longer report locations. + * Returns true if this provider has been set as enabled. This will be true unless explicitly + * set otherwise. */ - public abstract void onDisable(); + public boolean isEnabled() { + return mEnabled; + } /** - * Set the {@link ProviderRequest} requirements for this provider. - * <p>Each call to this method overrides all previous requests. - * <p>This method might trigger the provider to start returning - * locations, or to stop returning locations, depending on the - * parameters in the request. + * Reports a new location from this provider. */ - public abstract void onSetRequest(ProviderRequestUnbundled request, WorkSource source); + public void reportLocation(Location location) { + ILocationProviderManager manager = mManager; + if (manager != null) { + try { + manager.onReportLocation(location); + } catch (RemoteException | RuntimeException e) { + Log.w(mTag, e); + } + } + } + + protected void onInit() { + // call once so that providers designed for APIs pre-Q are not broken + onEnable(); + } + + /** + * @deprecated This callback will be invoked once when the provider is created to maintain + * backwards compatibility with providers not designed for Android Q and above. This method + * should only be implemented in location providers that need to support SDKs below Android Q. + * Even in this case, it is usually unnecessary to implement this callback with the correct + * design. This method may be removed in the future. + */ + @Deprecated + protected void onEnable() {} + + /** + * @deprecated This callback will be never be invoked on Android Q and above. This method should + * only be implemented in location providers that need to support SDKs below Android Q. Even in + * this case, it is usually unnecessary to implement this callback with the correct design. This + * method may be removed in the future. + */ + @Deprecated + protected void onDisable() {} + + /** + * Set the {@link ProviderRequest} requirements for this provider. Each call to this method + * overrides all previous requests. This method might trigger the provider to start returning + * locations, or to stop returning locations, depending on the parameters in the request. + */ + protected abstract void onSetRequest(ProviderRequestUnbundled request, WorkSource source); /** * Dump debug information. */ - public void onDump(FileDescriptor fd, PrintWriter pw, String[] args) { - } + protected void onDump(FileDescriptor fd, PrintWriter pw, String[] args) {} /** * This method will no longer be invoked. @@ -187,10 +231,12 @@ public abstract class LocationProviderBase { * <p>If extras is non-null, additional status information may be * added to it in the form of provider-specific key/value pairs. * - * @deprecated This method will no longer be invoked. + * @deprecated This callback will be never be invoked on Android Q and above. This method should + * only be implemented in location providers that need to support SDKs below Android Q. This + * method may be removed in the future. */ @Deprecated - public int onGetStatus(Bundle extras) { + protected int onGetStatus(Bundle extras) { return LocationProvider.AVAILABLE; } @@ -206,24 +252,64 @@ public abstract class LocationProviderBase { * * @return time of last status update in millis since last reboot * - * @deprecated This method will no longer be invoked. + * @deprecated This callback will be never be invoked on Android Q and above. This method should + * only be implemented in location providers that need to support SDKs below Android Q. This + * method may be removed in the future. */ @Deprecated - public long onGetStatusUpdateTime() { + protected long onGetStatusUpdateTime() { return 0; } /** - * Implements addditional location provider specific additional commands. - * - * @param command name of the command to send to the provider. - * @param extras optional arguments for the command (or null). - * The provider may optionally fill the extras Bundle with results from the command. - * - * @return true if the command succeeds. + * Implements location provider specific custom commands. The return value will be ignored on + * Android Q and above. */ - public boolean onSendExtraCommand(String command, Bundle extras) { - // default implementation + protected boolean onSendExtraCommand(@Nullable String command, @Nullable Bundle extras) { return false; } + + private final class Service extends ILocationProvider.Stub { + + @Override + public void setLocationProviderManager(ILocationProviderManager manager) { + synchronized (mBinder) { + try { + manager.onSetProperties(mProperties); + manager.onSetEnabled(mEnabled); + } catch (RemoteException e) { + Log.w(mTag, e); + } + + mManager = manager; + } + + onInit(); + } + + @Override + public void setRequest(ProviderRequest request, WorkSource ws) { + onSetRequest(new ProviderRequestUnbundled(request), ws); + } + + @Override + public int getStatus(Bundle extras) { + return onGetStatus(extras); + } + + @Override + public long getStatusUpdateTime() { + return onGetStatusUpdateTime(); + } + + @Override + public void sendExtraCommand(String command, Bundle extras) { + onSendExtraCommand(command, extras); + } + + @Override + public void dump(FileDescriptor fd, PrintWriter pw, String[] args) { + onDump(fd, pw, args); + } + } } diff --git a/location/lib/java/com/android/location/provider/ProviderRequestUnbundled.java b/location/lib/java/com/android/location/provider/ProviderRequestUnbundled.java index 6a8e61877e46..b825b58cd3e9 100644 --- a/location/lib/java/com/android/location/provider/ProviderRequestUnbundled.java +++ b/location/lib/java/com/android/location/provider/ProviderRequestUnbundled.java @@ -16,13 +16,13 @@ package com.android.location.provider; -import java.util.ArrayList; -import java.util.List; - import android.location.LocationRequest; import com.android.internal.location.ProviderRequest; +import java.util.ArrayList; +import java.util.List; + /** * This class is an interface to Provider Requests for unbundled applications. * @@ -46,6 +46,10 @@ public final class ProviderRequestUnbundled { return mRequest.interval; } + public boolean getForceLocation() { + return mRequest.forceLocation; + } + /** * Never null. */ diff --git a/media/java/android/media/AudioFormat.java b/media/java/android/media/AudioFormat.java index 24d27256ca03..793aa270e2fd 100644 --- a/media/java/android/media/AudioFormat.java +++ b/media/java/android/media/AudioFormat.java @@ -213,6 +213,8 @@ import java.util.Objects; * (e.g.{@link AudioTrack#getPlaybackHeadPosition() * AudioTrack.getPlaybackHeadPosition()}), * depending on the context where audio frame is used. + * For the purposes of {@link AudioFormat#getFrameSizeInBytes()}, a compressed data format + * returns a frame size of 1 byte. */ public final class AudioFormat implements Parcelable { @@ -707,6 +709,16 @@ public final class AudioFormat implements Parcelable { channelCount = 0; // position and index channel count mismatch } mChannelCount = channelCount; + + int frameSizeInBytes = 1; + try { + frameSizeInBytes = getBytesPerSample(mEncoding) * channelCount; + } catch (IllegalArgumentException iae) { + // ignored + } + // it is possible that channel count is 0, so ensure we return 1 for + // mFrameSizeInBytes for consistency. + mFrameSizeInBytes = frameSizeInBytes != 0 ? frameSizeInBytes : 1; } /** @hide */ @@ -734,6 +746,7 @@ public final class AudioFormat implements Parcelable { // Derived values computed in the constructor, cached here. private final int mChannelCount; + private final int mFrameSizeInBytes; /** * Return the encoding. @@ -788,6 +801,25 @@ public final class AudioFormat implements Parcelable { return mChannelCount; } + /** + * Return the frame size in bytes. + * + * For PCM or PCM packed compressed data this is the size of a sample multiplied + * by the channel count. For all other cases, including invalid/unset channel masks, + * this will return 1 byte. + * As an example, a stereo 16-bit PCM format would have a frame size of 4 bytes, + * an 8 channel float PCM format would have a frame size of 32 bytes, + * and a compressed data format (not packed in PCM) would have a frame size of 1 byte. + * + * Both {@link AudioRecord} or {@link AudioTrack} process data in multiples of + * this frame size. + * + * @return The audio frame size in bytes corresponding to the encoding and the channel mask. + */ + public int getFrameSizeInBytes() { + return mFrameSizeInBytes; + } + /** @hide */ public int getPropertySetMask() { return mPropertySetMask; diff --git a/packages/FusedLocation/src/com/android/location/fused/FusedLocationProvider.java b/packages/FusedLocation/src/com/android/location/fused/FusedLocationProvider.java index 87d6e4a137ac..be817d60e55b 100644 --- a/packages/FusedLocation/src/com/android/location/fused/FusedLocationProvider.java +++ b/packages/FusedLocation/src/com/android/location/fused/FusedLocationProvider.java @@ -23,7 +23,6 @@ import android.content.IntentFilter; import android.location.Criteria; import android.os.Handler; import android.os.Looper; -import android.os.Message; import android.os.UserHandle; import android.os.WorkSource; @@ -34,87 +33,53 @@ import com.android.location.provider.ProviderRequestUnbundled; import java.io.FileDescriptor; import java.io.PrintWriter; -public class FusedLocationProvider extends LocationProviderBase implements FusionEngine.Callback { +class FusedLocationProvider extends LocationProviderBase implements FusionEngine.Callback { private static final String TAG = "FusedLocationProvider"; private static ProviderPropertiesUnbundled PROPERTIES = ProviderPropertiesUnbundled.create( false, false, false, false, true, true, true, Criteria.POWER_LOW, Criteria.ACCURACY_FINE); - private static final int MSG_ENABLE = 1; - private static final int MSG_DISABLE = 2; - private static final int MSG_SET_REQUEST = 3; - + private final Context mContext; + private final Handler mHandler; private final FusionEngine mEngine; - private static class RequestWrapper { - public ProviderRequestUnbundled request; - public WorkSource source; - public RequestWrapper(ProviderRequestUnbundled request, WorkSource source) { - this.request = request; - this.source = source; + private final BroadcastReceiver mUserSwitchReceiver = new BroadcastReceiver() { + @Override + public void onReceive(Context context, Intent intent) { + String action = intent.getAction(); + if (Intent.ACTION_USER_SWITCHED.equals(action)) { + mEngine.switchUser(); + } } - } + }; - public FusedLocationProvider(Context context) { + FusedLocationProvider(Context context) { super(TAG, PROPERTIES); - mEngine = new FusionEngine(context, Looper.myLooper()); - // listen for user change - IntentFilter intentFilter = new IntentFilter(); - intentFilter.addAction(Intent.ACTION_USER_SWITCHED); - context.registerReceiverAsUser(new BroadcastReceiver() { - @Override - public void onReceive(Context context, Intent intent) { - String action = intent.getAction(); - if (Intent.ACTION_USER_SWITCHED.equals(action)) { - mEngine.switchUser(); - } - } - }, UserHandle.ALL, intentFilter, null, mHandler); + mContext = context; + mHandler = new Handler(Looper.myLooper()); + mEngine = new FusionEngine(context, Looper.myLooper(), this); } - /** - * For serializing requests to mEngine. - */ - private Handler mHandler = new Handler() { - @Override - public void handleMessage(Message msg) { - switch (msg.what) { - case MSG_ENABLE: - mEngine.init(FusedLocationProvider.this); - break; - case MSG_DISABLE: - mEngine.deinit(); - break; - case MSG_SET_REQUEST: - { - RequestWrapper wrapper = (RequestWrapper) msg.obj; - mEngine.setRequest(wrapper.request, wrapper.source); - break; - } - } - } - }; - - @Override - public void onEnable() { - mHandler.sendEmptyMessage(MSG_ENABLE); + void init() { + // listen for user change + mContext.registerReceiverAsUser(mUserSwitchReceiver, UserHandle.ALL, + new IntentFilter(Intent.ACTION_USER_SWITCHED), null, mHandler); } - @Override - public void onDisable() { - mHandler.sendEmptyMessage(MSG_DISABLE); + void destroy() { + mContext.unregisterReceiver(mUserSwitchReceiver); + mHandler.post(() -> mEngine.setRequest(null)); } @Override public void onSetRequest(ProviderRequestUnbundled request, WorkSource source) { - mHandler.obtainMessage(MSG_SET_REQUEST, new RequestWrapper(request, source)).sendToTarget(); + mHandler.post(() -> mEngine.setRequest(request)); } @Override public void onDump(FileDescriptor fd, PrintWriter pw, String[] args) { - // perform synchronously mEngine.dump(fd, pw, args); } } diff --git a/packages/FusedLocation/src/com/android/location/fused/FusedLocationService.java b/packages/FusedLocation/src/com/android/location/fused/FusedLocationService.java index 12966cfab888..75bb5eceab6d 100644 --- a/packages/FusedLocation/src/com/android/location/fused/FusedLocationService.java +++ b/packages/FusedLocation/src/com/android/location/fused/FusedLocationService.java @@ -21,27 +21,24 @@ import android.content.Intent; import android.os.IBinder; public class FusedLocationService extends Service { + private FusedLocationProvider mProvider; @Override public IBinder onBind(Intent intent) { if (mProvider == null) { - mProvider = new FusedLocationProvider(getApplicationContext()); + mProvider = new FusedLocationProvider(this); + mProvider.init(); } + return mProvider.getBinder(); } @Override - public boolean onUnbind(Intent intent) { - // make sure to stop performing work + public void onDestroy() { if (mProvider != null) { - mProvider.onDisable(); + mProvider.destroy(); + mProvider = null; } - return false; - } - - @Override - public void onDestroy() { - mProvider = null; } } diff --git a/packages/FusedLocation/src/com/android/location/fused/FusionEngine.java b/packages/FusedLocation/src/com/android/location/fused/FusionEngine.java index 7a4952484e46..e4610cf44636 100644 --- a/packages/FusedLocation/src/com/android/location/fused/FusionEngine.java +++ b/packages/FusedLocation/src/com/android/location/fused/FusionEngine.java @@ -16,14 +16,6 @@ package com.android.location.fused; -import java.io.FileDescriptor; -import java.io.PrintWriter; -import java.util.HashMap; - -import com.android.location.provider.LocationProviderBase; -import com.android.location.provider.LocationRequestUnbundled; -import com.android.location.provider.ProviderRequestUnbundled; - import android.content.Context; import android.location.Location; import android.location.LocationListener; @@ -32,9 +24,16 @@ import android.os.Bundle; import android.os.Looper; import android.os.Parcelable; import android.os.SystemClock; -import android.os.WorkSource; import android.util.Log; +import com.android.location.provider.LocationProviderBase; +import com.android.location.provider.LocationRequestUnbundled; +import com.android.location.provider.ProviderRequestUnbundled; + +import java.io.FileDescriptor; +import java.io.PrintWriter; +import java.util.HashMap; + public class FusionEngine implements LocationListener { public interface Callback { void reportLocation(Location location); @@ -47,72 +46,35 @@ public class FusionEngine implements LocationListener { public static final long SWITCH_ON_FRESHNESS_CLIFF_NS = 11 * 1000000000L; // 11 seconds - private final Context mContext; private final LocationManager mLocationManager; private final Looper mLooper; + private final Callback mCallback; // all fields are only used on mLooper thread. except for in dump() which is not thread-safe - private Callback mCallback; private Location mFusedLocation; private Location mGpsLocation; private Location mNetworkLocation; - private boolean mEnabled; private ProviderRequestUnbundled mRequest; private final HashMap<String, ProviderStats> mStats = new HashMap<>(); - public FusionEngine(Context context, Looper looper) { - mContext = context; + FusionEngine(Context context, Looper looper, Callback callback) { mLocationManager = (LocationManager) context.getSystemService(Context.LOCATION_SERVICE); mNetworkLocation = new Location(""); mNetworkLocation.setAccuracy(Float.MAX_VALUE); mGpsLocation = new Location(""); mGpsLocation.setAccuracy(Float.MAX_VALUE); mLooper = looper; + mCallback = callback; mStats.put(GPS, new ProviderStats()); mStats.put(NETWORK, new ProviderStats()); - - } - - public void init(Callback callback) { - Log.i(TAG, "engine started (" + mContext.getPackageName() + ")"); - mCallback = callback; - } - - /** - * Called to stop doing any work, and release all resources - * This can happen when a better fusion engine is installed - * in a different package, and this one is no longer needed. - * Called on mLooper thread - */ - public void deinit() { - mRequest = null; - disable(); - Log.i(TAG, "engine stopped (" + mContext.getPackageName() + ")"); - } - - /** Called on mLooper thread */ - public void enable() { - if (!mEnabled) { - mEnabled = true; - updateRequirements(); - } - } - - /** Called on mLooper thread */ - public void disable() { - if (mEnabled) { - mEnabled = false; - updateRequirements(); - } } /** Called on mLooper thread */ - public void setRequest(ProviderRequestUnbundled request, WorkSource source) { + public void setRequest(ProviderRequestUnbundled request) { mRequest = request; - mEnabled = request.getReportLocation(); updateRequirements(); } @@ -120,6 +82,7 @@ public class FusionEngine implements LocationListener { public boolean requested; public long requestTime; public long minTime; + @Override public String toString() { return (requested ? " REQUESTED" : " ---"); @@ -154,7 +117,7 @@ public class FusionEngine implements LocationListener { } private void updateRequirements() { - if (!mEnabled || mRequest == null) { + if (mRequest == null || !mRequest.getReportLocation()) { mRequest = null; disableProvider(NETWORK); disableProvider(GPS); @@ -200,29 +163,30 @@ public class FusionEngine implements LocationListener { * Test whether one location (a) is better to use than another (b). */ private static boolean isBetterThan(Location locationA, Location locationB) { - if (locationA == null) { - return false; - } - if (locationB == null) { - return true; - } - // A provider is better if the reading is sufficiently newer. Heading - // underground can cause GPS to stop reporting fixes. In this case it's - // appropriate to revert to cell, even when its accuracy is less. - if (locationA.getElapsedRealtimeNanos() > locationB.getElapsedRealtimeNanos() + SWITCH_ON_FRESHNESS_CLIFF_NS) { - return true; - } - - // A provider is better if it has better accuracy. Assuming both readings - // are fresh (and by that accurate), choose the one with the smaller - // accuracy circle. - if (!locationA.hasAccuracy()) { - return false; - } - if (!locationB.hasAccuracy()) { - return true; - } - return locationA.getAccuracy() < locationB.getAccuracy(); + if (locationA == null) { + return false; + } + if (locationB == null) { + return true; + } + // A provider is better if the reading is sufficiently newer. Heading + // underground can cause GPS to stop reporting fixes. In this case it's + // appropriate to revert to cell, even when its accuracy is less. + if (locationA.getElapsedRealtimeNanos() + > locationB.getElapsedRealtimeNanos() + SWITCH_ON_FRESHNESS_CLIFF_NS) { + return true; + } + + // A provider is better if it has better accuracy. Assuming both readings + // are fresh (and by that accurate), choose the one with the smaller + // accuracy circle. + if (!locationA.hasAccuracy()) { + return false; + } + if (!locationB.hasAccuracy()) { + return true; + } + return locationA.getAccuracy() < locationB.getAccuracy(); } private void updateFusedLocation() { @@ -252,9 +216,9 @@ public class FusionEngine implements LocationListener { } if (mCallback != null) { - mCallback.reportLocation(mFusedLocation); + mCallback.reportLocation(mFusedLocation); } else { - Log.w(TAG, "Location updates received while fusion engine not started"); + Log.w(TAG, "Location updates received while fusion engine not started"); } } @@ -272,19 +236,22 @@ public class FusionEngine implements LocationListener { /** Called on mLooper thread */ @Override - public void onStatusChanged(String provider, int status, Bundle extras) { } + public void onStatusChanged(String provider, int status, Bundle extras) { + } /** Called on mLooper thread */ @Override - public void onProviderEnabled(String provider) { } + public void onProviderEnabled(String provider) { + } /** Called on mLooper thread */ @Override - public void onProviderDisabled(String provider) { } + public void onProviderDisabled(String provider) { + } public void dump(FileDescriptor fd, PrintWriter pw, String[] args) { StringBuilder s = new StringBuilder(); - s.append("mEnabled=").append(mEnabled).append(' ').append(mRequest).append('\n'); + s.append(mRequest).append('\n'); s.append("fused=").append(mFusedLocation).append('\n'); s.append(String.format("gps %s\n", mGpsLocation)); s.append(" ").append(mStats.get(GPS)).append('\n'); diff --git a/packages/SettingsLib/ActionButtonsPreference/Android.bp b/packages/SettingsLib/ActionButtonsPreference/Android.bp index cd3fb0cc2143..e518e0b97c4b 100644 --- a/packages/SettingsLib/ActionButtonsPreference/Android.bp +++ b/packages/SettingsLib/ActionButtonsPreference/Android.bp @@ -1,5 +1,5 @@ android_library { - name: "SettingsLibActionButtonsPreference", + name: "ActionButtonsPreference", srcs: ["src/**/*.java"], resource_dirs: ["res"], diff --git a/packages/SettingsLib/Android.bp b/packages/SettingsLib/Android.bp index e588e9211a84..cc17b25d9a40 100644 --- a/packages/SettingsLib/Android.bp +++ b/packages/SettingsLib/Android.bp @@ -16,8 +16,8 @@ android_library { "SettingsLibAppPreference", "SettingsLibSearchWidget", "SettingsLibSettingsSpinner", - "SettingsLibLayoutPreference", - "SettingsLibActionButtonsPreference", + "SettingsLayoutPreference", + "ActionButtonsPreference", ], // ANDROIDMK TRANSLATION ERROR: unsupported assignment to LOCAL_SHARED_JAVA_LIBRARIES diff --git a/packages/SettingsLib/LayoutPreference/Android.bp b/packages/SettingsLib/SettingsLayoutPreference/Android.bp index a1f9a768c76c..489d3606ae15 100644 --- a/packages/SettingsLib/LayoutPreference/Android.bp +++ b/packages/SettingsLib/SettingsLayoutPreference/Android.bp @@ -1,5 +1,5 @@ android_library { - name: "SettingsLibLayoutPreference", + name: "SettingsLayoutPreference", srcs: ["src/**/*.java"], resource_dirs: ["res"], diff --git a/packages/SettingsLib/LayoutPreference/AndroidManifest.xml b/packages/SettingsLib/SettingsLayoutPreference/AndroidManifest.xml index 4b9f1ab8d6cc..4b9f1ab8d6cc 100644 --- a/packages/SettingsLib/LayoutPreference/AndroidManifest.xml +++ b/packages/SettingsLib/SettingsLayoutPreference/AndroidManifest.xml diff --git a/packages/SettingsLib/LayoutPreference/res/layout/layout_preference_frame.xml b/packages/SettingsLib/SettingsLayoutPreference/res/layout/layout_preference_frame.xml index ee4ce499396f..ee4ce499396f 100644 --- a/packages/SettingsLib/LayoutPreference/res/layout/layout_preference_frame.xml +++ b/packages/SettingsLib/SettingsLayoutPreference/res/layout/layout_preference_frame.xml diff --git a/packages/SettingsLib/LayoutPreference/res/layout/settings_entity_header.xml b/packages/SettingsLib/SettingsLayoutPreference/res/layout/settings_entity_header.xml index 01d9c00d94dd..01d9c00d94dd 100644 --- a/packages/SettingsLib/LayoutPreference/res/layout/settings_entity_header.xml +++ b/packages/SettingsLib/SettingsLayoutPreference/res/layout/settings_entity_header.xml diff --git a/packages/SettingsLib/LayoutPreference/res/values/styles.xml b/packages/SettingsLib/SettingsLayoutPreference/res/values/styles.xml index 805744baef10..805744baef10 100644 --- a/packages/SettingsLib/LayoutPreference/res/values/styles.xml +++ b/packages/SettingsLib/SettingsLayoutPreference/res/values/styles.xml diff --git a/packages/SettingsLib/LayoutPreference/src/com/android/settingslib/widget/LayoutPreference.java b/packages/SettingsLib/SettingsLayoutPreference/src/com/android/settingslib/widget/LayoutPreference.java index 2a635b0996e6..2a635b0996e6 100644 --- a/packages/SettingsLib/LayoutPreference/src/com/android/settingslib/widget/LayoutPreference.java +++ b/packages/SettingsLib/SettingsLayoutPreference/src/com/android/settingslib/widget/LayoutPreference.java diff --git a/proto/src/wifi.proto b/proto/src/wifi.proto index 1fda07499a33..e9ce737eb5a5 100644 --- a/proto/src/wifi.proto +++ b/proto/src/wifi.proto @@ -1344,6 +1344,27 @@ message WifiPowerStats { // Amount of time wifi is in tx (ms) optional int64 tx_time_ms = 5; + + // Amount of time kernel is active because of wifi data (ms) + optional int64 wifi_kernel_active_time_ms = 6; + + // Number of packets sent (tx) + optional int64 num_packets_tx = 7; + + // Number of bytes sent (tx) + optional int64 num_bytes_tx = 8; + + // Number of packets received (rx) + optional int64 num_packets_rx = 9; + + // Number of bytes sent (rx) + optional int64 num_bytes_rx = 10; + + // Amount of time wifi is in sleep (ms) + optional int64 sleep_time_ms = 11; + + // Amount of time wifi is scanning (ms) + optional int64 scan_time_ms = 12; } // Metrics for Wifi Wake diff --git a/services/autofill/java/com/android/server/autofill/Session.java b/services/autofill/java/com/android/server/autofill/Session.java index d76a5dff36d3..aef16b1e6dbf 100644 --- a/services/autofill/java/com/android/server/autofill/Session.java +++ b/services/autofill/java/com/android/server/autofill/Session.java @@ -1238,7 +1238,15 @@ final class Session implements RemoteFillService.FillServiceCallbacks, ViewState return; } - final UserData userData = mService.getUserData(); + final UserData packageUserData = lastResponse.getUserData(); + + final UserData userData; + if (packageUserData != null) { + // Replace default userData + userData = packageUserData; + } else { + userData = mService.getUserData(); + } for (int i = 0; i < mViewStates.size(); i++) { final ViewState viewState = mViewStates.valueAt(i); diff --git a/services/core/java/com/android/server/LocationManagerService.java b/services/core/java/com/android/server/LocationManagerService.java index da19e27b5b82..8b992ebcf059 100644 --- a/services/core/java/com/android/server/LocationManagerService.java +++ b/services/core/java/com/android/server/LocationManagerService.java @@ -17,8 +17,11 @@ package com.android.server; import static android.content.pm.PackageManager.PERMISSION_GRANTED; +import static android.location.LocationProvider.AVAILABLE; import static android.provider.Settings.Global.LOCATION_DISABLE_STATUS_CALLBACKS; +import static com.android.internal.util.Preconditions.checkState; + import android.annotation.NonNull; import android.annotation.Nullable; import android.app.ActivityManager; @@ -53,7 +56,6 @@ import android.location.ILocationManager; import android.location.INetInitiatedListener; import android.location.Location; import android.location.LocationManager; -import android.location.LocationProvider; import android.location.LocationRequest; import android.os.Binder; import android.os.Bundle; @@ -83,6 +85,7 @@ import com.android.internal.location.ProviderRequest; import com.android.internal.os.BackgroundThread; import com.android.internal.util.ArrayUtils; import com.android.internal.util.DumpUtils; +import com.android.server.location.AbstractLocationProvider; import com.android.server.location.ActivityRecognitionProxy; import com.android.server.location.GeocoderProxy; import com.android.server.location.GeofenceManager; @@ -94,7 +97,6 @@ import com.android.server.location.GnssNavigationMessageProvider; import com.android.server.location.GnssStatusListenerHelper; import com.android.server.location.LocationBlacklist; import com.android.server.location.LocationFudger; -import com.android.server.location.LocationProviderInterface; import com.android.server.location.LocationProviderProxy; import com.android.server.location.LocationRequestStatistics; import com.android.server.location.LocationRequestStatistics.PackageProviderKey; @@ -131,8 +133,6 @@ public class LocationManagerService extends ILocationManager.Stub { // Location resolution level: fine location data private static final int RESOLUTION_LEVEL_FINE = 2; - private static final String ACCESS_MOCK_LOCATION = - android.Manifest.permission.ACCESS_MOCK_LOCATION; private static final String ACCESS_LOCATION_EXTRA_COMMANDS = android.Manifest.permission.ACCESS_LOCATION_EXTRA_COMMANDS; private static final String INSTALL_LOCATION_PROVIDER = @@ -192,12 +192,6 @@ public class LocationManagerService extends ILocationManager.Stub { private IGpsGeofenceHardware mGpsGeofenceProxy; // --- fields below are protected by mLock --- - // Set of providers that are explicitly enabled - // Only used by passive, fused & test. Network & GPS are controlled separately, and not listed. - private final Set<String> mEnabledProviders = new HashSet<>(); - - // Set of providers that are explicitly disabled - private final Set<String> mDisabledProviders = new HashSet<>(); // Mock (test) providers private final HashMap<String, MockProvider> mMockProviders = @@ -207,15 +201,15 @@ public class LocationManagerService extends ILocationManager.Stub { private final HashMap<Object, Receiver> mReceivers = new HashMap<>(); // currently installed providers (with mocks replacing real providers) - private final ArrayList<LocationProviderInterface> mProviders = + private final ArrayList<LocationProvider> mProviders = new ArrayList<>(); // real providers, saved here when mocked out - private final HashMap<String, LocationProviderInterface> mRealProviders = + private final HashMap<String, LocationProvider> mRealProviders = new HashMap<>(); // mapping from provider name to provider - private final HashMap<String, LocationProviderInterface> mProvidersByName = + private final HashMap<String, LocationProvider> mProvidersByName = new HashMap<>(); // mapping from provider name to all its UpdateRecords @@ -270,13 +264,8 @@ public class LocationManagerService extends ILocationManager.Stub { PackageManagerInternal packageManagerInternal = LocalServices.getService( PackageManagerInternal.class); packageManagerInternal.setLocationPackagesProvider( - new PackageManagerInternal.PackagesProvider() { - @Override - public String[] getPackages(int userId) { - return mContext.getResources().getStringArray( - com.android.internal.R.array.config_locationProviderPackageNames); - } - }); + userId -> mContext.getResources().getStringArray( + com.android.internal.R.array.config_locationProviderPackageNames)); if (D) Log.d(TAG, "Constructed"); @@ -321,30 +310,17 @@ public class LocationManagerService extends ILocationManager.Stub { mAppOps.startWatchingMode(AppOpsManager.OP_COARSE_LOCATION, null, AppOpsManager.WATCH_FOREGROUND_CHANGES, callback); - PackageManager.OnPermissionsChangedListener permissionListener - = new PackageManager.OnPermissionsChangedListener() { - @Override - public void onPermissionsChanged(final int uid) { - synchronized (mLock) { - applyAllProviderRequirementsLocked(); - } + PackageManager.OnPermissionsChangedListener permissionListener = uid -> { + synchronized (mLock) { + applyAllProviderRequirementsLocked(); } }; mPackageManager.addOnPermissionsChangeListener(permissionListener); // listen for background/foreground changes - ActivityManager.OnUidImportanceListener uidImportanceListener - = new ActivityManager.OnUidImportanceListener() { - @Override - public void onUidImportance(final int uid, final int importance) { - mLocationHandler.post(new Runnable() { - @Override - public void run() { - onUidImportanceChanged(uid, importance); - } - }); - } - }; + ActivityManager.OnUidImportanceListener uidImportanceListener = + (uid, importance) -> mLocationHandler.post( + () -> onUidImportanceChanged(uid, importance)); mActivityManager.addOnUidImportanceListener(uidImportanceListener, FOREGROUND_IMPORTANCE_CUTOFF); @@ -356,7 +332,10 @@ public class LocationManagerService extends ILocationManager.Stub { // prepare providers loadProvidersLocked(); - updateProvidersLocked(); + updateProvidersSettingsLocked(); + for (LocationProvider provider : mProviders) { + applyRequirementsLocked(provider.getName()); + } } // listen for settings changes @@ -366,7 +345,7 @@ public class LocationManagerService extends ILocationManager.Stub { @Override public void onChange(boolean selfChange) { synchronized (mLock) { - updateProvidersLocked(); + updateProvidersSettingsLocked(); } } }, UserHandle.USER_ALL); @@ -377,7 +356,9 @@ public class LocationManagerService extends ILocationManager.Stub { @Override public void onChange(boolean selfChange) { synchronized (mLock) { - updateProvidersLocked(); + for (LocationProvider provider : mProviders) { + applyRequirementsLocked(provider.getName()); + } } } }, UserHandle.USER_ALL); @@ -402,7 +383,9 @@ public class LocationManagerService extends ILocationManager.Stub { public void onChange(boolean selfChange) { synchronized (mLock) { updateBackgroundThrottlingWhitelistLocked(); - updateProvidersLocked(); + for (LocationProvider provider : mProviders) { + applyRequirementsLocked(provider.getName()); + } } } }, UserHandle.USER_ALL); @@ -414,7 +397,6 @@ public class LocationManagerService extends ILocationManager.Stub { intentFilter.addAction(Intent.ACTION_USER_SWITCHED); intentFilter.addAction(Intent.ACTION_MANAGED_PROFILE_ADDED); intentFilter.addAction(Intent.ACTION_MANAGED_PROFILE_REMOVED); - intentFilter.addAction(Intent.ACTION_SHUTDOWN); mContext.registerReceiverAsUser(new BroadcastReceiver() { @Override @@ -425,12 +407,6 @@ public class LocationManagerService extends ILocationManager.Stub { } else if (Intent.ACTION_MANAGED_PROFILE_ADDED.equals(action) || Intent.ACTION_MANAGED_PROFILE_REMOVED.equals(action)) { updateUserProfiles(mCurrentUserId); - } else if (Intent.ACTION_SHUTDOWN.equals(action)) { - // shutdown only if UserId indicates whole system, not just one user - if (D) Log.d(TAG, "Shutdown received with UserId: " + getSendingUserId()); - if (getSendingUserId() == UserHandle.USER_ALL) { - shutdownComponents(); - } } } }, UserHandle.ALL, intentFilter, null, mLocationHandler); @@ -508,30 +484,13 @@ public class LocationManagerService extends ILocationManager.Stub { } /** - * Provides a way for components held by the {@link LocationManagerService} to clean-up - * gracefully on system's shutdown. - * - * NOTES: - * 1) Only provides a chance to clean-up on an opt-in basis. This guarantees back-compat - * support for components that do not wish to handle such event. - */ - private void shutdownComponents() { - if (D) Log.d(TAG, "Shutting down components..."); - - LocationProviderInterface gpsProvider = mProvidersByName.get(LocationManager.GPS_PROVIDER); - if (gpsProvider != null && gpsProvider.isEnabled()) { - gpsProvider.disable(); - } - } - - /** * Makes a list of userids that are related to the current user. This is * relevant when using managed profiles. Otherwise the list only contains * the current user. * * @param currentUserId the current user, who might have an alter-ego. */ - void updateUserProfiles(int currentUserId) { + private void updateUserProfiles(int currentUserId) { int[] profileIds = mUserManager.getProfileIdsWithDisabled(currentUserId); synchronized (mLock) { mCurrentUserProfiles = profileIds; @@ -620,22 +579,28 @@ public class LocationManagerService extends ILocationManager.Stub { private void loadProvidersLocked() { // create a passive location provider, which is always enabled - PassiveProvider passiveProvider = new PassiveProvider(this); - addProviderLocked(passiveProvider); - mEnabledProviders.add(passiveProvider.getName()); + LocationProvider passiveProviderManager = new LocationProvider( + LocationManager.PASSIVE_PROVIDER); + PassiveProvider passiveProvider = new PassiveProvider(passiveProviderManager); + + addProviderLocked(passiveProviderManager); mPassiveProvider = passiveProvider; if (GnssLocationProvider.isSupported()) { // Create a gps location provider - GnssLocationProvider gnssProvider = new GnssLocationProvider(mContext, this, + LocationProvider gnssProviderManager = new LocationProvider( + LocationManager.GPS_PROVIDER); + GnssLocationProvider gnssProvider = new GnssLocationProvider(mContext, + gnssProviderManager, mLocationHandler.getLooper()); + mGnssSystemInfoProvider = gnssProvider.getGnssSystemInfoProvider(); mGnssBatchingProvider = gnssProvider.getGnssBatchingProvider(); mGnssMetricsProvider = gnssProvider.getGnssMetricsProvider(); mGnssStatusProvider = gnssProvider.getGnssStatusProvider(); mNetInitiatedListener = gnssProvider.getNetInitiatedListener(); - addProviderLocked(gnssProvider); - mRealProviders.put(LocationManager.GPS_PROVIDER, gnssProvider); + addProviderLocked(gnssProviderManager); + mRealProviders.put(LocationManager.GPS_PROVIDER, gnssProviderManager); mGnssMeasurementsProvider = gnssProvider.getGnssMeasurementsProvider(); mGnssNavigationMessageProvider = gnssProvider.getGnssNavigationMessageProvider(); mGpsGeofenceProxy = gnssProvider.getGpsGeofenceProxy(); @@ -663,34 +628,38 @@ public class LocationManagerService extends ILocationManager.Stub { ensureFallbackFusedProviderPresentLocked(pkgs); // bind to network provider + + LocationProvider networkProviderManager = new LocationProvider( + LocationManager.NETWORK_PROVIDER); LocationProviderProxy networkProvider = LocationProviderProxy.createAndBind( mContext, - LocationManager.NETWORK_PROVIDER, + networkProviderManager, NETWORK_LOCATION_SERVICE_ACTION, com.android.internal.R.bool.config_enableNetworkLocationOverlay, com.android.internal.R.string.config_networkLocationProviderPackageName, com.android.internal.R.array.config_locationProviderPackageNames); if (networkProvider != null) { - mRealProviders.put(LocationManager.NETWORK_PROVIDER, networkProvider); + mRealProviders.put(LocationManager.NETWORK_PROVIDER, networkProviderManager); mProxyProviders.add(networkProvider); - addProviderLocked(networkProvider); + addProviderLocked(networkProviderManager); } else { Slog.w(TAG, "no network location provider found"); } // bind to fused provider - LocationProviderProxy fusedLocationProvider = LocationProviderProxy.createAndBind( + LocationProvider fusedProviderManager = new LocationProvider( + LocationManager.FUSED_PROVIDER); + LocationProviderProxy fusedProvider = LocationProviderProxy.createAndBind( mContext, - LocationManager.FUSED_PROVIDER, + fusedProviderManager, FUSED_LOCATION_SERVICE_ACTION, com.android.internal.R.bool.config_enableFusedLocationOverlay, com.android.internal.R.string.config_fusedLocationProviderPackageName, com.android.internal.R.array.config_locationProviderPackageNames); - if (fusedLocationProvider != null) { - addProviderLocked(fusedLocationProvider); - mProxyProviders.add(fusedLocationProvider); - mEnabledProviders.add(fusedLocationProvider.getName()); - mRealProviders.put(LocationManager.FUSED_PROVIDER, fusedLocationProvider); + if (fusedProvider != null) { + addProviderLocked(fusedProviderManager); + mProxyProviders.add(fusedProvider); + mRealProviders.put(LocationManager.FUSED_PROVIDER, fusedProviderManager); } else { Slog.e(TAG, "no fused location provider found", new IllegalStateException("Location service needs a fused location provider")); @@ -771,12 +740,9 @@ public class LocationManagerService extends ILocationManager.Stub { synchronized (mLock) { mLastLocation.clear(); mLastLocationCoarseInterval.clear(); - for (LocationProviderInterface p : mProviders) { - updateProviderListenersLocked(p.getName(), false); - } - mCurrentUserId = userId; updateUserProfiles(userId); - updateProvidersLocked(); + updateProvidersSettingsLocked(); + mCurrentUserId = userId; } } @@ -792,6 +758,165 @@ public class LocationManagerService extends ILocationManager.Stub { } } + private class LocationProvider implements AbstractLocationProvider.LocationProviderManager { + + private final String mName; + private AbstractLocationProvider mProvider; + + // whether the provider is enabled in location settings + private boolean mSettingsEnabled; + + // whether the provider considers itself enabled + private volatile boolean mEnabled; + + @Nullable + private volatile ProviderProperties mProperties; + + private LocationProvider(String name) { + mName = name; + // TODO: initialize settings enabled? + } + + @Override + public void onAttachProvider(AbstractLocationProvider provider, boolean initiallyEnabled) { + checkState(mProvider == null); + + // the provider is not yet fully constructed at this point, so we may not do anything + // except save a reference for later use here. do not call any provider methods. + mProvider = provider; + mEnabled = initiallyEnabled; + mProperties = null; + } + + public String getName() { + return mName; + } + + public boolean isEnabled() { + return mSettingsEnabled && mEnabled; + } + + @Nullable + public ProviderProperties getProperties() { + return mProperties; + } + + public void setRequest(ProviderRequest request, WorkSource workSource) { + mProvider.setRequest(request, workSource); + } + + public void dump(FileDescriptor fd, PrintWriter pw, String[] args) { + pw.println(mName + " provider:"); + pw.println(" setting=" + mSettingsEnabled); + pw.println(" enabled=" + mEnabled); + pw.println(" properties=" + mProperties); + mProvider.dump(fd, pw, args); + } + + public long getStatusUpdateTime() { + return mProvider.getStatusUpdateTime(); + } + + public int getStatus(Bundle extras) { + return mProvider.getStatus(extras); + } + + public void sendExtraCommand(String command, Bundle extras) { + mProvider.sendExtraCommand(command, extras); + } + + // called from any thread + @Override + public void onReportLocation(Location location) { + runOnHandler(() -> LocationManagerService.this.reportLocation(location, + mProvider == mPassiveProvider)); + } + + // called from any thread + @Override + public void onReportLocation(List<Location> locations) { + runOnHandler(() -> LocationManagerService.this.reportLocationBatch(locations)); + } + + // called from any thread + @Override + public void onSetEnabled(boolean enabled) { + runOnHandler(() -> { + if (enabled == mEnabled) { + return; + } + + mEnabled = enabled; + + if (!mSettingsEnabled) { + // this provider was disabled in settings anyways, so a change to it's own + // enabled status won't have any affect. + return; + } + + // traditionally clients can listen for changes to the LOCATION_PROVIDERS_ALLOWED + // setting to detect when providers are enabled or disabled (even though they aren't + // supposed to). to continue to support this we must force a change to this setting. + // we use the fused provider because this is forced to be always enabled in settings + // anyways, and so won't have any visible effect beyond triggering content observers + Settings.Secure.putStringForUser(mContext.getContentResolver(), + Settings.Secure.LOCATION_PROVIDERS_ALLOWED, + "+" + LocationManager.FUSED_PROVIDER, mCurrentUserId); + Settings.Secure.putStringForUser(mContext.getContentResolver(), + Settings.Secure.LOCATION_PROVIDERS_ALLOWED, + "-" + LocationManager.FUSED_PROVIDER, mCurrentUserId); + + synchronized (mLock) { + if (!enabled) { + // If any provider has been disabled, clear all last locations for all + // providers. This is to be on the safe side in case a provider has location + // derived from this disabled provider. + mLastLocation.clear(); + mLastLocationCoarseInterval.clear(); + } + + updateProviderListenersLocked(mName); + } + + mContext.sendBroadcastAsUser(new Intent(LocationManager.PROVIDERS_CHANGED_ACTION), + UserHandle.ALL); + }); + } + + @Override + public void onSetProperties(ProviderProperties properties) { + runOnHandler(() -> mProperties = properties); + } + + private void setSettingsEnabled(boolean enabled) { + synchronized (mLock) { + if (mSettingsEnabled == enabled) { + return; + } + + mSettingsEnabled = enabled; + if (!mSettingsEnabled) { + // if any provider has been disabled, clear all last locations for all + // providers. this is to be on the safe side in case a provider has location + // derived from this disabled provider. + mLastLocation.clear(); + mLastLocationCoarseInterval.clear(); + updateProviderListenersLocked(mName); + } else if (mEnabled) { + updateProviderListenersLocked(mName); + } + } + } + + private void runOnHandler(Runnable runnable) { + if (Looper.myLooper() == mLocationHandler.getLooper()) { + runnable.run(); + } else { + mLocationHandler.post(runnable); + } + } + } + /** * A wrapper class holding either an ILocationListener or a PendingIntent to receive * location updates. @@ -799,24 +924,24 @@ public class LocationManagerService extends ILocationManager.Stub { private final class Receiver implements IBinder.DeathRecipient, PendingIntent.OnFinished { private static final long WAKELOCK_TIMEOUT_MILLIS = 60 * 1000; final Identity mIdentity; - final int mAllowedResolutionLevel; // resolution level allowed to receiver + private final int mAllowedResolutionLevel; // resolution level allowed to receiver - final ILocationListener mListener; + private final ILocationListener mListener; final PendingIntent mPendingIntent; final WorkSource mWorkSource; // WorkSource for battery blame, or null to assign to caller. - final boolean mHideFromAppOps; // True if AppOps should not monitor this receiver. - final Object mKey; + private final boolean mHideFromAppOps; // True if AppOps should not monitor this receiver. + private final Object mKey; final HashMap<String, UpdateRecord> mUpdateRecords = new HashMap<>(); // True if app ops has started monitoring this receiver for locations. - boolean mOpMonitoring; + private boolean mOpMonitoring; // True if app ops has started monitoring this receiver for high power (gps) locations. - boolean mOpHighPowerMonitoring; - int mPendingBroadcasts; + private boolean mOpHighPowerMonitoring; + private int mPendingBroadcasts; PowerManager.WakeLock mWakeLock; - Receiver(ILocationListener listener, PendingIntent intent, int pid, int uid, + private Receiver(ILocationListener listener, PendingIntent intent, int pid, int uid, String packageName, WorkSource workSource, boolean hideFromAppOps) { mListener = listener; mPendingIntent = intent; @@ -891,9 +1016,10 @@ public class LocationManagerService extends ILocationManager.Stub { // See if receiver has any enabled update records. Also note if any update records // are high power (has a high power provider with an interval under a threshold). for (UpdateRecord updateRecord : mUpdateRecords.values()) { - if (isAllowedByCurrentUserSettingsLocked(updateRecord.mProvider)) { + if (isAllowedByUserSettingsLockedForUser(updateRecord.mProvider, + mCurrentUserId)) { requestingLocation = true; - LocationProviderInterface locationProvider + LocationManagerService.LocationProvider locationProvider = mProvidersByName.get(updateRecord.mProvider); ProviderProperties properties = locationProvider != null ? locationProvider.getProperties() : null; @@ -1040,7 +1166,7 @@ public class LocationManagerService extends ILocationManager.Stub { return true; } - public boolean callProviderEnabledLocked(String provider, boolean enabled) { + private boolean callProviderEnabledLocked(String provider, boolean enabled) { // First update AppOp monitoring. // An app may get/lose location access as providers are enabled/disabled. updateMonitoring(true); @@ -1242,7 +1368,7 @@ public class LocationManagerService extends ILocationManager.Stub { private class LinkedCallback implements IBinder.DeathRecipient { private final IBatchedLocationCallback mCallback; - public LinkedCallback(@NonNull IBatchedLocationCallback callback) { + private LinkedCallback(@NonNull IBatchedLocationCallback callback) { mCallback = callback; } @@ -1343,7 +1469,7 @@ public class LocationManagerService extends ILocationManager.Stub { checkCallerIsProvider(); // Currently used only for GNSS locations - update permissions check if changed - if (isAllowedByCurrentUserSettingsLocked(LocationManager.GPS_PROVIDER)) { + if (isAllowedByUserSettingsLockedForUser(LocationManager.GPS_PROVIDER, mCurrentUserId)) { if (mGnssBatchingCallback == null) { Slog.e(TAG, "reportLocationBatch() called without active Callback"); return; @@ -1358,29 +1484,17 @@ public class LocationManagerService extends ILocationManager.Stub { } } - private void addProviderLocked(LocationProviderInterface provider) { + private void addProviderLocked(LocationProvider provider) { mProviders.add(provider); mProvidersByName.put(provider.getName(), provider); } - private void removeProviderLocked(LocationProviderInterface provider) { - provider.disable(); + private void removeProviderLocked(LocationProvider provider) { mProviders.remove(provider); mProvidersByName.remove(provider.getName()); } /** - * Returns "true" if access to the specified location provider is allowed by the current - * user's settings. Access to all location providers is forbidden to non-location-provider - * processes belonging to background users. - * - * @param provider the name of the location provider - */ - private boolean isAllowedByCurrentUserSettingsLocked(String provider) { - return isAllowedByUserSettingsLockedForUser(provider, mCurrentUserId); - } - - /** * Returns "true" if access to the specified location provider is allowed by the specified * user's settings. Access to all location providers is forbidden to non-location-provider * processes belonging to background users. @@ -1389,13 +1503,28 @@ public class LocationManagerService extends ILocationManager.Stub { * @param userId the user id to query */ private boolean isAllowedByUserSettingsLockedForUser(String provider, int userId) { - if (mEnabledProviders.contains(provider)) { - return true; + if (LocationManager.PASSIVE_PROVIDER.equals(provider)) { + return isLocationEnabledForUser(userId); } - if (mDisabledProviders.contains(provider)) { - return false; + if (LocationManager.FUSED_PROVIDER.equals(provider)) { + return isLocationEnabledForUser(userId); + } + synchronized (mLock) { + if (mMockProviders.containsKey(provider)) { + return isLocationEnabledForUser(userId); + } + } + + long identity = Binder.clearCallingIdentity(); + try { + // Use system settings + ContentResolver cr = mContext.getContentResolver(); + String allowedProviders = Settings.Secure.getStringForUser( + cr, Settings.Secure.LOCATION_PROVIDERS_ALLOWED, userId); + return TextUtils.delimitedStringContains(allowedProviders, ',', provider); + } finally { + Binder.restoreCallingIdentity(identity); } - return isLocationProviderEnabledForUser(provider, userId); } @@ -1487,9 +1616,11 @@ public class LocationManagerService extends ILocationManager.Stub { // network and fused providers are ok with COARSE or FINE return RESOLUTION_LEVEL_COARSE; } else { - // mock providers - LocationProviderInterface lp = mMockProviders.get(provider); - if (lp != null) { + for (LocationProvider lp : mProviders) { + if (!lp.getName().equals(provider)) { + continue; + } + ProviderProperties properties = lp.getProperties(); if (properties != null) { if (properties.mRequiresSatellite) { @@ -1502,6 +1633,7 @@ public class LocationManagerService extends ILocationManager.Stub { } } } + return RESOLUTION_LEVEL_FINE; // if in doubt, require FINE } @@ -1556,7 +1688,7 @@ public class LocationManagerService extends ILocationManager.Stub { } private static String resolutionLevelToOpStr(int allowedResolutionLevel) { - switch(allowedResolutionLevel) { + switch (allowedResolutionLevel) { case RESOLUTION_LEVEL_COARSE: return AppOpsManager.OPSTR_COARSE_LOCATION; case RESOLUTION_LEVEL_FINE: @@ -1571,7 +1703,7 @@ public class LocationManagerService extends ILocationManager.Stub { } } - boolean reportLocationAccessNoThrow( + private boolean reportLocationAccessNoThrow( int pid, int uid, String packageName, int allowedResolutionLevel) { int op = resolutionLevelToOp(allowedResolutionLevel); if (op >= 0) { @@ -1583,7 +1715,8 @@ public class LocationManagerService extends ILocationManager.Stub { return getAllowedResolutionLevel(pid, uid) >= allowedResolutionLevel; } - boolean checkLocationAccess(int pid, int uid, String packageName, int allowedResolutionLevel) { + private boolean checkLocationAccess(int pid, int uid, String packageName, + int allowedResolutionLevel) { int op = resolutionLevelToOp(allowedResolutionLevel); if (op >= 0) { if (mAppOps.noteOp(op, uid, packageName) != AppOpsManager.MODE_ALLOWED) { @@ -1603,7 +1736,7 @@ public class LocationManagerService extends ILocationManager.Stub { ArrayList<String> out; synchronized (mLock) { out = new ArrayList<>(mProviders.size()); - for (LocationProviderInterface provider : mProviders) { + for (LocationProvider provider : mProviders) { String name = provider.getName(); if (LocationManager.FUSED_PROVIDER.equals(name)) { continue; @@ -1629,7 +1762,7 @@ public class LocationManagerService extends ILocationManager.Stub { try { synchronized (mLock) { out = new ArrayList<>(mProviders.size()); - for (LocationProviderInterface provider : mProviders) { + for (LocationProvider provider : mProviders) { String name = provider.getName(); if (LocationManager.FUSED_PROVIDER.equals(name)) { continue; @@ -1639,7 +1772,8 @@ public class LocationManagerService extends ILocationManager.Stub { && !isAllowedByUserSettingsLocked(name, uid, mCurrentUserId)) { continue; } - if (criteria != null && !LocationProvider.propertiesMeetCriteria( + if (criteria != null + && !android.location.LocationProvider.propertiesMeetCriteria( name, provider.getProperties(), criteria)) { continue; } @@ -1664,7 +1798,7 @@ public class LocationManagerService extends ILocationManager.Stub { */ @Override public String getBestProvider(Criteria criteria, boolean enabledOnly) { - String result = null; + String result; List<String> providers = getProviders(criteria, enabledOnly); if (!providers.isEmpty()) { @@ -1679,7 +1813,7 @@ public class LocationManagerService extends ILocationManager.Stub { return result; } - if (D) Log.d(TAG, "getBestProvider(" + criteria + ", " + enabledOnly + ")=" + result); + if (D) Log.d(TAG, "getBestProvider(" + criteria + ", " + enabledOnly + ")=" + null); return null; } @@ -1695,51 +1829,32 @@ public class LocationManagerService extends ILocationManager.Stub { @Override public boolean providerMeetsCriteria(String provider, Criteria criteria) { - LocationProviderInterface p = mProvidersByName.get(provider); + LocationProvider p = mProvidersByName.get(provider); if (p == null) { throw new IllegalArgumentException("provider=" + provider); } - boolean result = LocationProvider.propertiesMeetCriteria( + boolean result = android.location.LocationProvider.propertiesMeetCriteria( p.getName(), p.getProperties(), criteria); if (D) Log.d(TAG, "providerMeetsCriteria(" + provider + ", " + criteria + ")=" + result); return result; } - private void updateProvidersLocked() { - boolean changesMade = false; - for (int i = mProviders.size() - 1; i >= 0; i--) { - LocationProviderInterface p = mProviders.get(i); - boolean isEnabled = p.isEnabled(); - String name = p.getName(); - boolean shouldBeEnabled = isAllowedByCurrentUserSettingsLocked(name); - if (isEnabled && !shouldBeEnabled) { - updateProviderListenersLocked(name, false); - // If any provider has been disabled, clear all last locations for all providers. - // This is to be on the safe side in case a provider has location derived from - // this disabled provider. - mLastLocation.clear(); - mLastLocationCoarseInterval.clear(); - changesMade = true; - } else if (!isEnabled && shouldBeEnabled) { - updateProviderListenersLocked(name, true); - changesMade = true; - } - } - if (changesMade) { - mContext.sendBroadcastAsUser(new Intent(LocationManager.PROVIDERS_CHANGED_ACTION), - UserHandle.ALL); - mContext.sendBroadcastAsUser(new Intent(LocationManager.MODE_CHANGED_ACTION), - UserHandle.ALL); + private void updateProvidersSettingsLocked() { + for (LocationProvider p : mProviders) { + p.setSettingsEnabled(isAllowedByUserSettingsLockedForUser(p.getName(), mCurrentUserId)); } - } - private void updateProviderListenersLocked(String provider, boolean enabled) { - int listeners = 0; + mContext.sendBroadcastAsUser(new Intent(LocationManager.MODE_CHANGED_ACTION), + UserHandle.ALL); + } - LocationProviderInterface p = mProvidersByName.get(provider); + private void updateProviderListenersLocked(String provider) { + LocationProvider p = mProvidersByName.get(provider); if (p == null) return; + boolean enabled = p.isEnabled(); + ArrayList<Receiver> deadReceivers = null; ArrayList<UpdateRecord> records = mRecordsByProvider.get(provider); @@ -1753,7 +1868,6 @@ public class LocationManagerService extends ILocationManager.Stub { } deadReceivers.add(record.mReceiver); } - listeners++; } } } @@ -1764,16 +1878,11 @@ public class LocationManagerService extends ILocationManager.Stub { } } - if (enabled) { - p.enable(); - applyRequirementsLocked(provider); - } else { - p.disable(); - } + applyRequirementsLocked(provider); } private void applyRequirementsLocked(String provider) { - LocationProviderInterface p = mProvidersByName.get(provider); + LocationProvider p = mProvidersByName.get(provider); if (p == null) return; ArrayList<UpdateRecord> records = mRecordsByProvider.get(provider); @@ -1785,10 +1894,10 @@ public class LocationManagerService extends ILocationManager.Stub { resolver, Settings.Global.LOCATION_BACKGROUND_THROTTLE_INTERVAL_MS, DEFAULT_BACKGROUND_THROTTLE_INTERVAL_MS); - // initialize the low power mode to true and set to false if any of the records requires - providerRequest.lowPowerMode = true; - if (records != null) { + if (p.isEnabled() && records != null && !records.isEmpty()) { + // initialize the low power mode to true and set to false if any of the records requires + providerRequest.lowPowerMode = true; for (UpdateRecord record : records) { if (isCurrentProfile(UserHandle.getUserId(record.mReceiver.mIdentity.mUid))) { if (checkLocationAccess( @@ -1881,7 +1990,7 @@ public class LocationManagerService extends ILocationManager.Stub { public String[] getBackgroundThrottlingWhitelist() { synchronized (mLock) { return mBackgroundThrottlePackageWhitelist.toArray( - new String[mBackgroundThrottlePackageWhitelist.size()]); + new String[0]); } } @@ -1928,17 +2037,17 @@ public class LocationManagerService extends ILocationManager.Stub { private class UpdateRecord { final String mProvider; - final LocationRequest mRealRequest; // original request from client + private final LocationRequest mRealRequest; // original request from client LocationRequest mRequest; // possibly throttled version of the request - final Receiver mReceiver; - boolean mIsForegroundUid; - Location mLastFixBroadcast; - long mLastStatusBroadcast; + private final Receiver mReceiver; + private boolean mIsForegroundUid; + private Location mLastFixBroadcast; + private long mLastStatusBroadcast; /** * Note: must be constructed with lock held. */ - UpdateRecord(String provider, LocationRequest request, Receiver receiver) { + private UpdateRecord(String provider, LocationRequest request, Receiver receiver) { mProvider = provider; mRealRequest = request; mRequest = request; @@ -1964,7 +2073,7 @@ public class LocationManagerService extends ILocationManager.Stub { /** * Method to be called when record changes foreground/background */ - void updateForeground(boolean isForeground){ + private void updateForeground(boolean isForeground) { mIsForegroundUid = isForeground; mRequestStatistics.updateForeground( mReceiver.mIdentity.mPackageName, mProvider, isForeground); @@ -1973,7 +2082,7 @@ public class LocationManagerService extends ILocationManager.Stub { /** * Method to be called when a record will no longer be used. */ - void disposeLocked(boolean removeReceiver) { + private void disposeLocked(boolean removeReceiver) { mRequestStatistics.stopRequesting(mReceiver.mIdentity.mPackageName, mProvider); // remove from mRecordsByProvider @@ -1986,13 +2095,11 @@ public class LocationManagerService extends ILocationManager.Stub { // remove from Receiver#mUpdateRecords HashMap<String, UpdateRecord> receiverRecords = mReceiver.mUpdateRecords; - if (receiverRecords != null) { - receiverRecords.remove(this.mProvider); + receiverRecords.remove(this.mProvider); - // and also remove the Receiver if it has no more update records - if (receiverRecords.size() == 0) { - removeUpdatesLocked(mReceiver); - } + // and also remove the Receiver if it has no more update records + if (receiverRecords.size() == 0) { + removeUpdatesLocked(mReceiver); } } @@ -2076,7 +2183,7 @@ public class LocationManagerService extends ILocationManager.Stub { private void checkPackageName(String packageName) { if (packageName == null) { - throw new SecurityException("invalid package name: " + packageName); + throw new SecurityException("invalid package name: " + null); } int uid = Binder.getCallingUid(); String[] packages = mPackageManager.getPackagesForUid(uid); @@ -2091,7 +2198,7 @@ public class LocationManagerService extends ILocationManager.Stub { private void checkPendingIntent(PendingIntent intent) { if (intent == null) { - throw new IllegalArgumentException("invalid pending intent: " + intent); + throw new IllegalArgumentException("invalid pending intent: " + null); } } @@ -2143,7 +2250,7 @@ public class LocationManagerService extends ILocationManager.Stub { synchronized (mLock) { Receiver recevier = checkListenerOrIntentLocked(listener, intent, pid, uid, packageName, workSource, hideFromAppOps); - requestLocationUpdatesLocked(sanitizedRequest, recevier, pid, uid, packageName); + requestLocationUpdatesLocked(sanitizedRequest, recevier, uid, packageName); } } finally { Binder.restoreCallingIdentity(identity); @@ -2151,7 +2258,7 @@ public class LocationManagerService extends ILocationManager.Stub { } private void requestLocationUpdatesLocked(LocationRequest request, Receiver receiver, - int pid, int uid, String packageName) { + int uid, String packageName) { // Figure out the provider. Either its explicitly request (legacy use cases), or // use the fused provider if (request == null) request = DEFAULT_LOCATION_REQUEST; @@ -2160,7 +2267,7 @@ public class LocationManagerService extends ILocationManager.Stub { throw new IllegalArgumentException("provider name must not be null"); } - LocationProviderInterface provider = mProvidersByName.get(name); + LocationProvider provider = mProvidersByName.get(name); if (provider == null) { throw new IllegalArgumentException("provider doesn't exist: " + name); } @@ -2179,8 +2286,7 @@ public class LocationManagerService extends ILocationManager.Stub { oldRecord.disposeLocked(false); } - boolean isProviderEnabled = isAllowedByUserSettingsLocked(name, uid, mCurrentUserId); - if (isProviderEnabled) { + if (provider.isEnabled()) { applyRequirementsLocked(name); } else { // Notify the listener that updates are currently disabled @@ -2200,10 +2306,8 @@ public class LocationManagerService extends ILocationManager.Stub { final int uid = Binder.getCallingUid(); synchronized (mLock) { - WorkSource workSource = null; - boolean hideFromAppOps = false; Receiver receiver = checkListenerOrIntentLocked(listener, intent, pid, uid, - packageName, workSource, hideFromAppOps); + packageName, null, false); // providers may use public location API's, need to clear identity long identity = Binder.clearCallingIdentity(); @@ -2242,22 +2346,12 @@ public class LocationManagerService extends ILocationManager.Stub { // update provider for (String provider : providers) { - // If provider is already disabled, don't need to do anything - if (!isAllowedByCurrentUserSettingsLocked(provider)) { - continue; - } - applyRequirementsLocked(provider); } } private void applyAllProviderRequirementsLocked() { - for (LocationProviderInterface p : mProviders) { - // If provider is already disabled, don't need to do anything - if (!isAllowedByCurrentUserSettingsLocked(p.getName())) { - continue; - } - + for (LocationProvider p : mProviders) { applyRequirementsLocked(p.getName()); } } @@ -2297,7 +2391,7 @@ public class LocationManagerService extends ILocationManager.Stub { // or use the fused provider String name = request.getProvider(); if (name == null) name = LocationManager.FUSED_PROVIDER; - LocationProviderInterface provider = mProvidersByName.get(name); + LocationProvider provider = mProvidersByName.get(name); if (provider == null) return null; if (!isAllowedByUserSettingsLocked(name, uid, mCurrentUserId)) return null; @@ -2320,7 +2414,7 @@ public class LocationManagerService extends ILocationManager.Stub { location.getElapsedRealtimeNanos() / NANOS_PER_MILLI; if ((locationAgeMs > mLastLocationMaxAgeMs) && (mAppOps.unsafeCheckOp(op, uid, packageName) - == AppOpsManager.MODE_FOREGROUND)) { + == AppOpsManager.MODE_FOREGROUND)) { return null; } @@ -2364,7 +2458,7 @@ public class LocationManagerService extends ILocationManager.Stub { } return false; } - LocationProviderInterface p = null; + LocationProvider p = null; String provider = location.getProvider(); if (provider != null) { p = mProvidersByName.get(provider); @@ -2376,7 +2470,7 @@ public class LocationManagerService extends ILocationManager.Stub { return false; } synchronized (mLock) { - if (!isAllowedByCurrentUserSettingsLocked(provider)) { + if (!isAllowedByUserSettingsLockedForUser(provider, mCurrentUserId)) { if (D) { Log.d(TAG, "Location disabled in Settings for current user:" + mCurrentUserId); } @@ -2496,11 +2590,13 @@ public class LocationManagerService extends ILocationManager.Stub { @Override public void removeGnssMeasurementsListener(IGnssMeasurementsListener listener) { - if (mGnssMeasurementsProvider != null) { - synchronized (mLock) { - mGnssMeasurementsListeners.remove(listener.asBinder()); - mGnssMeasurementsProvider.removeListener(listener); - } + if (mGnssMeasurementsProvider == null) { + return; + } + + synchronized (mLock) { + mGnssMeasurementsListeners.remove(listener.asBinder()); + mGnssMeasurementsProvider.removeListener(listener); } } @@ -2559,10 +2655,11 @@ public class LocationManagerService extends ILocationManager.Stub { } synchronized (mLock) { - LocationProviderInterface p = mProvidersByName.get(provider); + LocationProvider p = mProvidersByName.get(provider); if (p == null) return false; - return p.sendExtraCommand(command, extras); + p.sendExtraCommand(command, extras); + return true; } } @@ -2587,14 +2684,10 @@ public class LocationManagerService extends ILocationManager.Stub { */ @Override public ProviderProperties getProviderProperties(String provider) { - if (mProvidersByName.get(provider) == null) { - return null; - } - checkResolutionLevelIsSufficientForProviderUse(getCallerAllowedResolutionLevel(), provider); - LocationProviderInterface p; + LocationProvider p; synchronized (mLock) { p = mProvidersByName.get(provider); } @@ -2610,25 +2703,25 @@ public class LocationManagerService extends ILocationManager.Stub { */ @Override public String getNetworkProviderPackage() { - LocationProviderInterface p; + LocationProvider p; synchronized (mLock) { - if (mProvidersByName.get(LocationManager.NETWORK_PROVIDER) == null) { - return null; - } p = mProvidersByName.get(LocationManager.NETWORK_PROVIDER); } - if (p instanceof LocationProviderProxy) { - return ((LocationProviderProxy) p).getConnectedPackageName(); + if (p == null) { + return null; + } + if (p.mProvider instanceof LocationProviderProxy) { + return ((LocationProviderProxy) p.mProvider).getConnectedPackageName(); } return null; } /** - * Returns the current location enabled/disabled status for a user + * Returns the current location enabled/disabled status for a user * - * @param userId the id of the user - * @return true if location is enabled + * @param userId the id of the user + * @return true if location is enabled */ @Override public boolean isLocationEnabledForUser(int userId) { @@ -2646,7 +2739,7 @@ public class LocationManagerService extends ILocationManager.Stub { return false; } final List<String> providerList = Arrays.asList(allowedProviders.split(",")); - for(String provider : mRealProviders.keySet()) { + for (String provider : mRealProviders.keySet()) { if (provider.equals(LocationManager.PASSIVE_PROVIDER) || provider.equals(LocationManager.FUSED_PROVIDER)) { continue; @@ -2663,16 +2756,16 @@ public class LocationManagerService extends ILocationManager.Stub { } /** - * Enable or disable location for a user + * Enable or disable location for a user * - * @param enabled true to enable location, false to disable location - * @param userId the id of the user + * @param enabled true to enable location, false to disable location + * @param userId the id of the user */ @Override public void setLocationEnabledForUser(boolean enabled, int userId) { mContext.enforceCallingPermission( - android.Manifest.permission.WRITE_SECURE_SETTINGS, - "Requires WRITE_SECURE_SETTINGS permission"); + android.Manifest.permission.WRITE_SECURE_SETTINGS, + "Requires WRITE_SECURE_SETTINGS permission"); // Check INTERACT_ACROSS_USERS permission if userId is not current user id. checkInteractAcrossUsersPermission(userId); @@ -2687,7 +2780,7 @@ public class LocationManagerService extends ILocationManager.Stub { allProvidersSet.addAll(allRealProviders); // When disabling location, disable gps and network provider that could have been // enabled by location mode api. - if (enabled == false) { + if (!enabled) { allProvidersSet.add(LocationManager.GPS_PROVIDER); allProvidersSet.add(LocationManager.NETWORK_PROVIDER); } @@ -2722,93 +2815,48 @@ public class LocationManagerService extends ILocationManager.Stub { } /** - * Returns the current enabled/disabled status of a location provider and user + * Returns the current enabled/disabled status of a location provider and user * - * @param provider name of the provider - * @param userId the id of the user - * @return true if the provider exists and is enabled + * @param providerName name of the provider + * @param userId the id of the user + * @return true if the provider exists and is enabled */ @Override - public boolean isProviderEnabledForUser(String provider, int userId) { + public boolean isProviderEnabledForUser(String providerName, int userId) { // Check INTERACT_ACROSS_USERS permission if userId is not current user id. checkInteractAcrossUsersPermission(userId); - // Fused provider is accessed indirectly via criteria rather than the provider-based APIs, - // so we discourage its use - if (LocationManager.FUSED_PROVIDER.equals(provider)) return false; - - int uid = Binder.getCallingUid(); - synchronized (mLock) { - LocationProviderInterface p = mProvidersByName.get(provider); - return p != null - && isAllowedByUserSettingsLocked(provider, uid, userId); + if (!isLocationEnabledForUser(userId)) { + return false; } - } - - /** - * Enable or disable a single location provider. - * - * @param provider name of the provider - * @param enabled true to enable the provider. False to disable the provider - * @param userId the id of the user to set - * @return true if the value was set, false on errors - */ - @Override - public boolean setProviderEnabledForUser(String provider, boolean enabled, int userId) { - mContext.enforceCallingPermission( - android.Manifest.permission.WRITE_SECURE_SETTINGS, - "Requires WRITE_SECURE_SETTINGS permission"); - - // Check INTERACT_ACROSS_USERS permission if userId is not current user id. - checkInteractAcrossUsersPermission(userId); // Fused provider is accessed indirectly via criteria rather than the provider-based APIs, // so we discourage its use - if (LocationManager.FUSED_PROVIDER.equals(provider)) return false; + if (LocationManager.FUSED_PROVIDER.equals(providerName)) return false; long identity = Binder.clearCallingIdentity(); try { + LocationProvider provider; synchronized (mLock) { - // No such provider exists - if (!mProvidersByName.containsKey(provider)) return false; - - // If it is a test provider, do not write to Settings.Secure - if (mMockProviders.containsKey(provider)) { - setTestProviderEnabled(provider, enabled); - return true; - } - - // to ensure thread safety, we write the provider name with a '+' or '-' - // and let the SettingsProvider handle it rather than reading and modifying - // the list of enabled providers. - String providerChange = (enabled ? "+" : "-") + provider; - return Settings.Secure.putStringForUser( - mContext.getContentResolver(), Settings.Secure.LOCATION_PROVIDERS_ALLOWED, - providerChange, userId); + provider = mProvidersByName.get(providerName); } + return provider != null && provider.isEnabled(); } finally { Binder.restoreCallingIdentity(identity); } } /** - * Read location provider status from Settings.Secure + * Enable or disable a single location provider. * - * @param provider the location provider to query - * @param userId the user id to query - * @return true if the provider is enabled + * @param provider name of the provider + * @param enabled true to enable the provider. False to disable the provider + * @param userId the id of the user to set + * @return true if the value was set, false on errors */ - private boolean isLocationProviderEnabledForUser(String provider, int userId) { - long identity = Binder.clearCallingIdentity(); - try { - // Use system settings - ContentResolver cr = mContext.getContentResolver(); - String allowedProviders = Settings.Secure.getStringForUser( - cr, Settings.Secure.LOCATION_PROVIDERS_ALLOWED, userId); - return TextUtils.delimitedStringContains(allowedProviders, ',', provider); - } finally { - Binder.restoreCallingIdentity(identity); - } + @Override + public boolean setProviderEnabledForUser(String provider, boolean enabled, int userId) { + return false; } /** @@ -2940,7 +2988,7 @@ public class LocationManagerService extends ILocationManager.Stub { long now = SystemClock.elapsedRealtime(); String provider = (passive ? LocationManager.PASSIVE_PROVIDER : location.getProvider()); // Skip if the provider is unknown. - LocationProviderInterface p = mProvidersByName.get(provider); + LocationProvider p = mProvidersByName.get(provider); if (p == null) return; updateLastLocationLocked(location, provider); // mLastLocation should have been updated from the updateLastLocationLocked call above. @@ -3052,7 +3100,7 @@ public class LocationManagerService extends ILocationManager.Stub { LOCATION_DISABLE_STATUS_CALLBACKS, 1) == 0) { long prevStatusUpdateTime = r.mLastStatusBroadcast; if ((newStatusUpdateTime > prevStatusUpdateTime) - && (prevStatusUpdateTime != 0 || status != LocationProvider.AVAILABLE)) { + && (prevStatusUpdateTime != 0 || status != AVAILABLE)) { r.mLastStatusBroadcast = newStatusUpdateTime; if (!receiver.callStatusChangedLocked(provider, status, extras)) { @@ -3097,8 +3145,8 @@ public class LocationManagerService extends ILocationManager.Stub { /** * Updates last location with the given location * - * @param location new location to update - * @param provider Location provider to update for + * @param location new location to update + * @param provider Location provider to update for */ private void updateLastLocationLocked(Location location, String provider) { Location noGPSLocation = location.getExtraLocation(Location.EXTRA_NO_GPS_LOCATION); @@ -3153,13 +3201,11 @@ public class LocationManagerService extends ILocationManager.Stub { } synchronized (mLock) { - if (isAllowedByCurrentUserSettingsLocked(provider)) { - if (!passive) { - // notify passive provider of the new location - mPassiveProvider.updateLocation(myLocation); - } - handleLocationChangedLocked(myLocation, passive); + if (!passive) { + // notify passive provider of the new location + mPassiveProvider.updateLocation(myLocation); } + handleLocationChangedLocked(myLocation, passive); } } @@ -3244,13 +3290,12 @@ public class LocationManagerService extends ILocationManager.Stub { if (LocationManager.GPS_PROVIDER.equals(name) || LocationManager.NETWORK_PROVIDER.equals(name) || LocationManager.FUSED_PROVIDER.equals(name)) { - LocationProviderInterface p = mProvidersByName.get(name); + LocationProvider p = mProvidersByName.get(name); if (p != null) { removeProviderLocked(p); } } addTestProviderLocked(name, properties); - updateProvidersLocked(); } Binder.restoreCallingIdentity(identity); } @@ -3259,9 +3304,12 @@ public class LocationManagerService extends ILocationManager.Stub { if (mProvidersByName.get(name) != null) { throw new IllegalArgumentException("Provider \"" + name + "\" already exists"); } - MockProvider provider = new MockProvider(name, this, properties); + + LocationProvider provider = new LocationProvider(name); + MockProvider mockProvider = new MockProvider(provider, properties); + addProviderLocked(provider); - mMockProviders.put(name, provider); + mMockProviders.put(name, mockProvider); mLastLocation.put(name, null); mLastLocationCoarseInterval.put(name, null); } @@ -3273,28 +3321,25 @@ public class LocationManagerService extends ILocationManager.Stub { } synchronized (mLock) { - - // These methods can't be called after removing the test provider, so first make sure - // we don't leave anything dangling. - clearTestProviderEnabled(provider, opPackageName); - clearTestProviderLocation(provider, opPackageName); - MockProvider mockProvider = mMockProviders.remove(provider); if (mockProvider == null) { throw new IllegalArgumentException("Provider \"" + provider + "\" unknown"); } + long identity = Binder.clearCallingIdentity(); - removeProviderLocked(mProvidersByName.get(provider)); + try { + removeProviderLocked(mProvidersByName.get(provider)); - // reinstate real provider if available - LocationProviderInterface realProvider = mRealProviders.get(provider); - if (realProvider != null) { - addProviderLocked(realProvider); + // reinstate real provider if available + LocationProvider realProvider = mRealProviders.get(provider); + if (realProvider != null) { + addProviderLocked(realProvider); + } + mLastLocation.put(provider, null); + mLastLocationCoarseInterval.put(provider, null); + } finally { + Binder.restoreCallingIdentity(identity); } - mLastLocation.put(provider, null); - mLastLocationCoarseInterval.put(provider, null); - updateProvidersLocked(); - Binder.restoreCallingIdentity(identity); } } @@ -3324,23 +3369,11 @@ public class LocationManagerService extends ILocationManager.Stub { // clear calling identity so INSTALL_LOCATION_PROVIDER permission is not required long identity = Binder.clearCallingIdentity(); - mockProvider.setLocation(mock); - Binder.restoreCallingIdentity(identity); - } - } - - @Override - public void clearTestProviderLocation(String provider, String opPackageName) { - if (!canCallerAccessMockLocation(opPackageName)) { - return; - } - - synchronized (mLock) { - MockProvider mockProvider = mMockProviders.get(provider); - if (mockProvider == null) { - throw new IllegalArgumentException("Provider \"" + provider + "\" unknown"); + try { + mockProvider.setLocation(mock); + } finally { + Binder.restoreCallingIdentity(identity); } - mockProvider.clearLocation(); } } @@ -3349,47 +3382,18 @@ public class LocationManagerService extends ILocationManager.Stub { if (!canCallerAccessMockLocation(opPackageName)) { return; } - setTestProviderEnabled(provider, enabled); - } - /** Enable or disable a test location provider. */ - private void setTestProviderEnabled(String provider, boolean enabled) { synchronized (mLock) { MockProvider mockProvider = mMockProviders.get(provider); if (mockProvider == null) { throw new IllegalArgumentException("Provider \"" + provider + "\" unknown"); } long identity = Binder.clearCallingIdentity(); - if (enabled) { - mockProvider.enable(); - mEnabledProviders.add(provider); - mDisabledProviders.remove(provider); - } else { - mockProvider.disable(); - mEnabledProviders.remove(provider); - mDisabledProviders.add(provider); - } - updateProvidersLocked(); - Binder.restoreCallingIdentity(identity); - } - } - - @Override - public void clearTestProviderEnabled(String provider, String opPackageName) { - if (!canCallerAccessMockLocation(opPackageName)) { - return; - } - - synchronized (mLock) { - MockProvider mockProvider = mMockProviders.get(provider); - if (mockProvider == null) { - throw new IllegalArgumentException("Provider \"" + provider + "\" unknown"); + try { + mockProvider.setEnabled(enabled); + } finally { + Binder.restoreCallingIdentity(identity); } - long identity = Binder.clearCallingIdentity(); - mEnabledProviders.remove(provider); - mDisabledProviders.remove(provider); - updateProvidersLocked(); - Binder.restoreCallingIdentity(identity); } } @@ -3449,10 +3453,11 @@ public class LocationManagerService extends ILocationManager.Stub { + identity.mPackageName + ": " + isThrottlingExemptLocked(identity)); } pw.println(" Overlay Provider Packages:"); - for (LocationProviderInterface provider : mProviders) { - if (provider instanceof LocationProviderProxy) { + for (LocationProvider provider : mProviders) { + if (provider.mProvider instanceof LocationProviderProxy) { pw.println(" " + provider.getName() + ": " - + ((LocationProviderProxy) provider).getConnectedPackageName()); + + ((LocationProviderProxy) provider.mProvider) + .getConnectedPackageName()); } } pw.println(" Historical Records by Provider:"); @@ -3478,25 +3483,12 @@ public class LocationManagerService extends ILocationManager.Stub { mGeofenceManager.dump(pw); - if (mEnabledProviders.size() > 0) { - pw.println(" Enabled Providers:"); - for (String i : mEnabledProviders) { - pw.println(" " + i); - } - - } - if (mDisabledProviders.size() > 0) { - pw.println(" Disabled Providers:"); - for (String i : mDisabledProviders) { - pw.println(" " + i); - } - } pw.append(" "); mBlacklist.dump(pw); if (mMockProviders.size() > 0) { pw.println(" Mock Providers:"); for (Map.Entry<String, MockProvider> i : mMockProviders.entrySet()) { - i.getValue().dump(pw, " "); + i.getValue().dump(fd, pw, args); } } @@ -3513,13 +3505,7 @@ public class LocationManagerService extends ILocationManager.Stub { if (args.length > 0 && "short".equals(args[0])) { return; } - for (LocationProviderInterface provider : mProviders) { - pw.print(provider.getName() + " Internal State"); - if (provider instanceof LocationProviderProxy) { - LocationProviderProxy proxy = (LocationProviderProxy) provider; - pw.print(" (" + proxy.getConnectedPackageName() + ")"); - } - pw.println(":"); + for (LocationProvider provider : mProviders) { provider.dump(fd, pw, args); } if (mGnssBatchingInProgress) { diff --git a/services/core/java/com/android/server/ServiceWatcher.java b/services/core/java/com/android/server/ServiceWatcher.java index 574f54a51eb1..d09823efb6fa 100644 --- a/services/core/java/com/android/server/ServiceWatcher.java +++ b/services/core/java/com/android/server/ServiceWatcher.java @@ -16,9 +16,7 @@ package com.android.server; -import android.annotation.MainThread; import android.annotation.Nullable; -import android.annotation.WorkerThread; import android.app.ActivityManager; import android.content.BroadcastReceiver; import android.content.ComponentName; @@ -168,13 +166,13 @@ public class ServiceWatcher implements ServiceConnection { // called on handler thread @GuardedBy("mBindLock") protected void onBind() { - + Preconditions.checkState(Looper.myLooper() == mHandler.getLooper()); } // called on handler thread @GuardedBy("mBindLock") protected void onUnbind() { - + Preconditions.checkState(Looper.myLooper() == mHandler.getLooper()); } /** @@ -205,12 +203,12 @@ public class ServiceWatcher implements ServiceConnection { @Override public void onPackageRemoved(String packageName, int uid) { - bindBestPackage(Objects.equals(packageName, getCurrentPackageName())); + bindBestPackage(Objects.equals(packageName, getCurrentPackageName())); } @Override public boolean onPackageChanged(String packageName, int uid, String[] components) { - bindBestPackage(Objects.equals(packageName, getCurrentPackageName())); + bindBestPackage(Objects.equals(packageName, getCurrentPackageName())); return super.onPackageChanged(packageName, uid, components); } }.register(mContext, UserHandle.ALL, true, mHandler); @@ -243,20 +241,16 @@ public class ServiceWatcher implements ServiceConnection { return true; } - /** Returns thje name of the currently connected package or null. */ + /** Returns the name of the currently connected package or null. */ @Nullable public String getCurrentPackageName() { ComponentName bestComponent = mBestComponent; return bestComponent == null ? null : bestComponent.getPackageName(); } - public int getCurrentPackageVersion() { - return mBestVersion; - } - /** - * Runs the given BinderRunner if currently connected. Returns true if it was run, and false - * otherwise. All invocations to runOnBinder are run serially. + * Runs the given BinderRunner if currently connected. All invocations to runOnBinder are run + * serially. */ public final void runOnBinder(BinderRunner runner) { synchronized (mBindLock) { @@ -267,7 +261,7 @@ public class ServiceWatcher implements ServiceConnection { } catch (Exception e) { // remote exceptions cannot be allowed to crash system server Log.e(TAG, "exception while while running " + runner + " on " + service - + " from " + mBestComponent.toShortString(), e); + + " from " + this, e); } } } @@ -280,14 +274,6 @@ public class ServiceWatcher implements ServiceConnection { UserHandle.USER_SYSTEM).isEmpty(); } - /** - * Searches and binds to the best package, or do nothing if the best package - * is already bound, unless force rebinding is requested. - * - * @param forceRebind Force a rebinding to the best package if it's already - * bound. - */ - @WorkerThread private void bindBestPackage(boolean forceRebind) { Preconditions.checkState(Looper.myLooper() == mHandler.getLooper()); @@ -365,7 +351,6 @@ public class ServiceWatcher implements ServiceConnection { } } - @WorkerThread private void bind(ComponentName component, int version, int userId) { Preconditions.checkState(Looper.myLooper() == mHandler.getLooper()); @@ -382,7 +367,6 @@ public class ServiceWatcher implements ServiceConnection { UserHandle.of(userId)); } - @WorkerThread private void unbind() { Preconditions.checkState(Looper.myLooper() == mHandler.getLooper()); @@ -396,7 +380,6 @@ public class ServiceWatcher implements ServiceConnection { mBestUserId = UserHandle.USER_NULL; } - @MainThread @Override public final void onServiceConnected(ComponentName component, IBinder binder) { mHandler.post(() -> { @@ -410,7 +393,6 @@ public class ServiceWatcher implements ServiceConnection { }); } - @MainThread @Override public final void onServiceDisconnected(ComponentName component) { mHandler.post(() -> { diff --git a/services/core/java/com/android/server/TelephonyRegistry.java b/services/core/java/com/android/server/TelephonyRegistry.java index a2cbfaa02bfb..b04ae1746d18 100644 --- a/services/core/java/com/android/server/TelephonyRegistry.java +++ b/services/core/java/com/android/server/TelephonyRegistry.java @@ -67,7 +67,9 @@ import com.android.server.am.BatteryStatsService; import java.io.FileDescriptor; import java.io.PrintWriter; import java.util.ArrayList; +import java.util.HashMap; import java.util.List; +import java.util.Map; import java.util.NoSuchElementException; /** @@ -196,6 +198,8 @@ public class TelephonyRegistry extends ITelephonyRegistry.Stub { private ArrayList<List<PhysicalChannelConfig>> mPhysicalChannelConfigs; + private Map<Integer, List<EmergencyNumber>> mEmergencyNumberList; + private int[] mSrvccState; private int mDefaultSubId = SubscriptionManager.INVALID_SUBSCRIPTION_ID; @@ -229,8 +233,9 @@ public class TelephonyRegistry extends ITelephonyRegistry.Stub { | PhoneStateListener.LISTEN_CELL_INFO; static final int ENFORCE_PHONE_STATE_PERMISSION_MASK = - PhoneStateListener.LISTEN_CALL_FORWARDING_INDICATOR | - PhoneStateListener.LISTEN_MESSAGE_WAITING_INDICATOR; + PhoneStateListener.LISTEN_CALL_FORWARDING_INDICATOR + | PhoneStateListener.LISTEN_MESSAGE_WAITING_INDICATOR + | PhoneStateListener.LISTEN_EMERGENCY_NUMBER_LIST; static final int PRECISE_PHONE_STATE_PERMISSION_MASK = PhoneStateListener.LISTEN_PRECISE_CALL_STATE | @@ -357,6 +362,7 @@ public class TelephonyRegistry extends ITelephonyRegistry.Stub { mCellInfo = new ArrayList<List<CellInfo>>(); mSrvccState = new int[numPhones]; mPhysicalChannelConfigs = new ArrayList<List<PhysicalChannelConfig>>(); + mEmergencyNumberList = new HashMap<>(); for (int i = 0; i < numPhones; i++) { mCallState[i] = TelephonyManager.CALL_STATE_IDLE; mDataActivity[i] = TelephonyManager.DATA_ACTIVITY_NONE; @@ -752,6 +758,13 @@ public class TelephonyRegistry extends ITelephonyRegistry.Stub { remove(r.binder); } } + if ((events & PhoneStateListener.LISTEN_EMERGENCY_NUMBER_LIST) != 0) { + try { + r.callback.onEmergencyNumberListChanged(mEmergencyNumberList); + } catch (RemoteException ex) { + remove(r.binder); + } + } if ((events & PhoneStateListener.LISTEN_PHONE_CAPABILITY_CHANGE) != 0) { try { r.callback.onPhoneCapabilityChanged(mPhoneCapability); @@ -1665,10 +1678,30 @@ public class TelephonyRegistry extends ITelephonyRegistry.Stub { } @Override - public void notifyEmergencyNumberList(List<EmergencyNumber> emergencyNumberList) { - // TODO checkPermission, modify Listener constent documentation - // TODO implement multisim emergency number list update in listener - // TODO implement PhoneStateListenerTest + public void notifyEmergencyNumberList() { + if (!checkNotifyPermission("notifyEmergencyNumberList()")) { + return; + } + + synchronized (mRecords) { + mEmergencyNumberList = TelephonyManager.getDefault().getCurrentEmergencyNumberList(); + + for (Record r : mRecords) { + if (r.matchPhoneStateListenerEvent( + PhoneStateListener.LISTEN_EMERGENCY_NUMBER_LIST)) { + try { + r.callback.onEmergencyNumberListChanged(mEmergencyNumberList); + if (VDBG) { + log("notifyEmergencyNumberList: emergencyNumberList= " + + mEmergencyNumberList); + } + } catch (RemoteException ex) { + mRemoveList.add(r.binder); + } + } + } + handleRemoveListLocked(); + } } @@ -1710,6 +1743,7 @@ public class TelephonyRegistry extends ITelephonyRegistry.Stub { pw.println("mPhoneCapability=" + mPhoneCapability); pw.println("mPreferredDataSubId=" + mPreferredDataSubId); pw.println("mRadioPowerState=" + mRadioPowerState); + pw.println("mEmergencyNumberList=" + mEmergencyNumberList); pw.decreaseIndent(); diff --git a/services/core/java/com/android/server/location/AbstractLocationProvider.java b/services/core/java/com/android/server/location/AbstractLocationProvider.java new file mode 100644 index 000000000000..4c7c420214bd --- /dev/null +++ b/services/core/java/com/android/server/location/AbstractLocationProvider.java @@ -0,0 +1,149 @@ +/* + * Copyright (C) 2010 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.server.location; + +import android.location.Location; +import android.location.LocationProvider; +import android.os.Bundle; +import android.os.WorkSource; + +import com.android.internal.location.ProviderProperties; +import com.android.internal.location.ProviderRequest; + +import java.io.FileDescriptor; +import java.io.PrintWriter; +import java.util.List; + +/** + * Location Manager's interface for location providers. + * + * @hide + */ +public abstract class AbstractLocationProvider { + + /** + * Interface for communicating from a location provider back to the location service. + */ + public interface LocationProviderManager { + + /** + * Called on location provider construction to make the location service aware of this + * provider and what it's initial enabled/disabled state should be. + */ + void onAttachProvider(AbstractLocationProvider locationProvider, boolean initiallyEnabled); + + /** + * May be called to inform the location service of a change in this location provider's + * enabled/disabled state. + */ + void onSetEnabled(boolean enabled); + + /** + * May be called to inform the location service of a change in this location provider's + * properties. + */ + void onSetProperties(ProviderProperties properties); + + /** + * May be called to inform the location service that this provider has a new location + * available. + */ + void onReportLocation(Location location); + + /** + * May be called to inform the location service that this provider has a new location + * available. + */ + void onReportLocation(List<Location> locations); + } + + private final LocationProviderManager mLocationProviderManager; + + protected AbstractLocationProvider(LocationProviderManager locationProviderManager) { + this(locationProviderManager, true); + } + + protected AbstractLocationProvider(LocationProviderManager locationProviderManager, + boolean initiallyEnabled) { + mLocationProviderManager = locationProviderManager; + mLocationProviderManager.onAttachProvider(this, initiallyEnabled); + } + + /** + * Call this method to report a new location. May be called from any thread. + */ + protected void reportLocation(Location location) { + mLocationProviderManager.onReportLocation(location); + } + + /** + * Call this method to report a new location. May be called from any thread. + */ + protected void reportLocation(List<Location> locations) { + mLocationProviderManager.onReportLocation(locations); + } + + /** + * Call this method to report a change in provider enabled/disabled status. May be called from + * any thread. + */ + protected void setEnabled(boolean enabled) { + mLocationProviderManager.onSetEnabled(enabled); + } + + /** + * Call this method to report a change in provider properties. May be called from + * any thread. + */ + protected void setProperties(ProviderProperties properties) { + mLocationProviderManager.onSetProperties(properties); + } + + /** + * Called when the location service delivers a new request for fulfillment to the provider. + * Replaces any previous requests completely. + */ + public abstract void setRequest(ProviderRequest request, WorkSource source); + + /** + * Called to dump debug or log information. + */ + public abstract void dump(FileDescriptor fd, PrintWriter pw, String[] args); + + /** + * Retrieves the current status of the provider. + * + * @deprecated Will be removed in a future release. + */ + @Deprecated + public int getStatus(Bundle extras) { + return LocationProvider.AVAILABLE; + } + + /** + * Retrieves the last update time of the status of the provider. + * + * @deprecated Will be removed in a future release. + */ + @Deprecated + public long getStatusUpdateTime() { + return 0; + } + + /** Sends a custom command to this provider. */ + public abstract void sendExtraCommand(String command, Bundle extras); +} diff --git a/services/core/java/com/android/server/location/GnssLocationProvider.java b/services/core/java/com/android/server/location/GnssLocationProvider.java index b7c77a2350a2..29e1878b739a 100644 --- a/services/core/java/com/android/server/location/GnssLocationProvider.java +++ b/services/core/java/com/android/server/location/GnssLocationProvider.java @@ -32,7 +32,6 @@ import android.location.GnssMeasurementsEvent; import android.location.GnssNavigationMessage; import android.location.GnssStatus; import android.location.IGpsGeofenceHardware; -import android.location.ILocationManager; import android.location.INetInitiatedListener; import android.location.Location; import android.location.LocationListener; @@ -82,6 +81,10 @@ import java.io.FileDescriptor; import java.io.FileInputStream; import java.io.IOException; import java.io.PrintWriter; +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; import java.util.ArrayList; import java.util.Arrays; import java.util.HashMap; @@ -95,8 +98,18 @@ import java.util.Properties; * * {@hide} */ -public class GnssLocationProvider extends LocationProviderInterface - implements InjectNtpTimeCallback, GnssSatelliteBlacklistCallback { +public class GnssLocationProvider extends AbstractLocationProvider implements + InjectNtpTimeCallback, + GnssSatelliteBlacklistCallback { + + /** + * Indicates that this method is a native entry point. Useful purely for IDEs which can + * understand entry points, and thus eliminate incorrect warnings about methods not used. + */ + @Target(ElementType.METHOD) + @Retention(RetentionPolicy.SOURCE) + private @interface NativeEntryPoint { + } private static final String TAG = "GnssLocationProvider"; @@ -247,7 +260,7 @@ public class GnssLocationProvider extends LocationProviderInterface } public void set(int svCount, int meanCn0, int maxCn0) { - synchronized(this) { + synchronized (this) { mSvCount = svCount; mMeanCn0 = meanCn0; mMaxCn0 = maxCn0; @@ -256,7 +269,7 @@ public class GnssLocationProvider extends LocationProviderInterface } public void reset() { - set(0,0,0); + set(0, 0, 0); } // Also used by outside methods to add to other bundles @@ -312,7 +325,7 @@ public class GnssLocationProvider extends LocationProviderInterface MAX_RETRY_INTERVAL); // true if we are enabled, protected by this - private boolean mEnabled; + private boolean mEnabled = true; // states for injecting ntp and downloading xtra data private static final int STATE_PENDING_NETWORK = 0; @@ -326,9 +339,6 @@ public class GnssLocationProvider extends LocationProviderInterface // true if GPS is navigating private boolean mNavigating; - // true if GPS engine is on - private boolean mEngineOn; - // requested frequency of fixes, in milliseconds private int mFixInterval = 1000; @@ -378,7 +388,6 @@ public class GnssLocationProvider extends LocationProviderInterface private boolean mSuplEsEnabled = false; private final Context mContext; - private final ILocationManager mILocationManager; private final LocationExtras mLocationExtras = new LocationExtras(); private final GnssStatusListenerHelper mGnssStatusListenerHelper; private final GnssSatelliteBlacklistHelper mGnssSatelliteBlacklistHelper; @@ -465,17 +474,22 @@ public class GnssLocationProvider extends LocationProviderInterface return; } - if (action.equals(ALARM_WAKEUP)) { - startNavigating(false); - } else if (action.equals(ALARM_TIMEOUT)) { - hibernate(); - } else if (PowerManager.ACTION_POWER_SAVE_MODE_CHANGED.equals(action) - || PowerManager.ACTION_DEVICE_IDLE_MODE_CHANGED.equals(action) - || Intent.ACTION_SCREEN_OFF.equals(action) - || Intent.ACTION_SCREEN_ON.equals(action)) { - updateLowPowerMode(); - } else if (action.equals(SIM_STATE_CHANGED)) { - subscriptionOrSimChanged(context); + switch (action) { + case ALARM_WAKEUP: + startNavigating(false); + break; + case ALARM_TIMEOUT: + hibernate(); + break; + case PowerManager.ACTION_POWER_SAVE_MODE_CHANGED: + case PowerManager.ACTION_DEVICE_IDLE_MODE_CHANGED: + case Intent.ACTION_SCREEN_OFF: + case Intent.ACTION_SCREEN_ON: + updateLowPowerMode(); + break; + case SIM_STATE_CHANGED: + subscriptionOrSimChanged(context); + break; } } }; @@ -493,9 +507,7 @@ public class GnssLocationProvider extends LocationProviderInterface */ @Override public void onUpdateSatelliteBlacklist(int[] constellations, int[] svids) { - mHandler.post(()->{ - native_set_satellite_blacklist(constellations, svids); - }); + mHandler.post(() -> native_set_satellite_blacklist(constellations, svids)); } private void subscriptionOrSimChanged(Context context) { @@ -558,7 +570,7 @@ public class GnssLocationProvider extends LocationProviderInterface } interface SetCarrierProperty { - public boolean set(int value); + boolean set(int value); } private void reloadGpsProperties(Context context, Properties properties) { @@ -573,7 +585,7 @@ public class GnssLocationProvider extends LocationProviderInterface /* * Overlay carrier properties from a debug configuration file. */ - loadPropertiesFromFile(DEBUG_PROPERTIES_FILE, properties); + loadPropertiesFromFile(properties); // TODO: we should get rid of C2K specific setting. setSuplHostPort(properties.getProperty("SUPL_HOST"), properties.getProperty("SUPL_PORT")); @@ -589,15 +601,15 @@ public class GnssLocationProvider extends LocationProviderInterface if (native_is_gnss_configuration_supported()) { Map<String, SetCarrierProperty> map = new HashMap<String, SetCarrierProperty>() { { - put("SUPL_VER", (val) -> native_set_supl_version(val)); - put("SUPL_MODE", (val) -> native_set_supl_mode(val)); - put("SUPL_ES", (val) -> native_set_supl_es(val)); - put("LPP_PROFILE", (val) -> native_set_lpp_profile(val)); + put("SUPL_VER", GnssLocationProvider::native_set_supl_version); + put("SUPL_MODE", GnssLocationProvider::native_set_supl_mode); + put("SUPL_ES", GnssLocationProvider::native_set_supl_es); + put("LPP_PROFILE", GnssLocationProvider::native_set_lpp_profile); put("A_GLONASS_POS_PROTOCOL_SELECT", - (val) -> native_set_gnss_pos_protocol_select(val)); + GnssLocationProvider::native_set_gnss_pos_protocol_select); put("USE_EMERGENCY_PDN_FOR_EMERGENCY_SUPL", - (val) -> native_set_emergency_supl_pdn(val)); - put("GPS_LOCK", (val) -> native_set_gps_lock(val)); + GnssLocationProvider::native_set_emergency_supl_pdn); + put("GPS_LOCK", GnssLocationProvider::native_set_gps_lock); } }; @@ -608,7 +620,7 @@ public class GnssLocationProvider extends LocationProviderInterface try { int propertyValueInt = Integer.decode(propertyValueString); boolean result = entry.getValue().set(propertyValueInt); - if (result == false) { + if (!result) { Log.e(TAG, "Unable to set " + propertyName); } } catch (NumberFormatException e) { @@ -650,10 +662,9 @@ public class GnssLocationProvider extends LocationProviderInterface } } - private boolean loadPropertiesFromFile(String filename, - Properties properties) { + private void loadPropertiesFromFile(Properties properties) { try { - File file = new File(filename); + File file = new File(DEBUG_PROPERTIES_FILE); FileInputStream stream = null; try { stream = new FileInputStream(file); @@ -663,16 +674,15 @@ public class GnssLocationProvider extends LocationProviderInterface } } catch (IOException e) { - if (DEBUG) Log.d(TAG, "Could not open GPS configuration file " + filename); - return false; + if (DEBUG) Log.d(TAG, "Could not open GPS configuration file " + DEBUG_PROPERTIES_FILE); } - return true; } - public GnssLocationProvider(Context context, ILocationManager ilocationManager, + public GnssLocationProvider(Context context, LocationProviderManager locationProviderManager, Looper looper) { + super(locationProviderManager, true); + mContext = context; - mILocationManager = ilocationManager; // Create a wake lock mPowerManager = (PowerManager) mContext.getSystemService(Context.POWER_SERVICE); @@ -749,19 +759,20 @@ public class GnssLocationProvider extends LocationProviderInterface mHandler.post(mGnssSatelliteBlacklistHelper::updateSatelliteBlacklist); mGnssBatchingProvider = new GnssBatchingProvider(); mGnssGeofenceProvider = new GnssGeofenceProvider(); - } - /** - * Returns the name of this provider. - */ - @Override - public String getName() { - return LocationManager.GPS_PROVIDER; - } + IntentFilter intentFilter = new IntentFilter(); + intentFilter.addAction(Intent.ACTION_SHUTDOWN); + mContext.registerReceiverAsUser(new BroadcastReceiver() { + @Override + public void onReceive(Context context, Intent intent) { + if (getSendingUserId() == UserHandle.USER_ALL) { + mEnabled = false; + handleDisable(); + } + } + }, UserHandle.ALL, intentFilter, null, mHandler); - @Override - public ProviderProperties getProperties() { - return PROPERTIES; + setProperties(PROPERTIES); } /** @@ -826,9 +837,9 @@ public class GnssLocationProvider extends LocationProviderInterface locationManager.requestLocationUpdates(provider, LOCATION_UPDATE_MIN_TIME_INTERVAL_MILLIS, /*minDistance=*/ 0, locationListener, mHandler.getLooper()); - locationListener.numLocationUpdateRequest++; + locationListener.mNumLocationUpdateRequest++; mHandler.postDelayed(() -> { - if (--locationListener.numLocationUpdateRequest == 0) { + if (--locationListener.mNumLocationUpdateRequest == 0) { Log.i(TAG, String.format("Removing location updates from %s provider.", provider)); locationManager.removeUpdates(locationListener); @@ -891,43 +902,40 @@ public class GnssLocationProvider extends LocationProviderInterface // hold wake lock while task runs mDownloadXtraWakeLock.acquire(DOWNLOAD_XTRA_DATA_TIMEOUT_MS); Log.i(TAG, "WakeLock acquired by handleDownloadXtraData()"); - AsyncTask.THREAD_POOL_EXECUTOR.execute(new Runnable() { - @Override - public void run() { - GpsXtraDownloader xtraDownloader = new GpsXtraDownloader(mProperties); - byte[] data = xtraDownloader.downloadXtraData(); - if (data != null) { - if (DEBUG) Log.d(TAG, "calling native_inject_xtra_data"); - native_inject_xtra_data(data, data.length); - mXtraBackOff.reset(); - } + AsyncTask.THREAD_POOL_EXECUTOR.execute(() -> { + GpsXtraDownloader xtraDownloader = new GpsXtraDownloader(mProperties); + byte[] data = xtraDownloader.downloadXtraData(); + if (data != null) { + if (DEBUG) Log.d(TAG, "calling native_inject_xtra_data"); + native_inject_xtra_data(data, data.length); + mXtraBackOff.reset(); + } - sendMessage(DOWNLOAD_XTRA_DATA_FINISHED, 0, null); + sendMessage(DOWNLOAD_XTRA_DATA_FINISHED, 0, null); - if (data == null) { - // try again later - // since this is delayed and not urgent we do not hold a wake lock here - mHandler.sendEmptyMessageDelayed(DOWNLOAD_XTRA_DATA, - mXtraBackOff.nextBackoffMillis()); - } + if (data == null) { + // try again later + // since this is delayed and not urgent we do not hold a wake lock here + mHandler.sendEmptyMessageDelayed(DOWNLOAD_XTRA_DATA, + mXtraBackOff.nextBackoffMillis()); + } - // Release wake lock held by task, synchronize on mLock in case multiple - // download tasks overrun. - synchronized (mLock) { - if (mDownloadXtraWakeLock.isHeld()) { - // This wakelock may have time-out, if a timeout was specified. - // Catch (and ignore) any timeout exceptions. - try { - mDownloadXtraWakeLock.release(); - if (DEBUG) Log.d(TAG, "WakeLock released by handleDownloadXtraData()"); - } catch (Exception e) { - Log.i(TAG, "Wakelock timeout & release race exception in " - + "handleDownloadXtraData()", e); - } - } else { - Log.e(TAG, "WakeLock expired before release in " - + "handleDownloadXtraData()"); + // Release wake lock held by task, synchronize on mLock in case multiple + // download tasks overrun. + synchronized (mLock) { + if (mDownloadXtraWakeLock.isHeld()) { + // This wakelock may have time-out, if a timeout was specified. + // Catch (and ignore) any timeout exceptions. + try { + mDownloadXtraWakeLock.release(); + if (DEBUG) Log.d(TAG, "WakeLock released by handleDownloadXtraData()"); + } catch (Exception e) { + Log.i(TAG, "Wakelock timeout & release race exception in " + + "handleDownloadXtraData()", e); } + } else { + Log.e(TAG, "WakeLock expired before release in " + + "handleDownloadXtraData()"); } } }); @@ -940,21 +948,6 @@ public class GnssLocationProvider extends LocationProviderInterface } } - /** - * Enables this provider. When enabled, calls to getStatus() - * must be handled. Hardware may be started up - * when the provider is enabled. - */ - @Override - public void enable() { - synchronized (mLock) { - if (mEnabled) return; - mEnabled = true; - } - - sendMessage(ENABLE, 1, null); - } - private void setSuplHostPort(String hostString, String portString) { if (hostString != null) { mSuplServerHost = hostString; @@ -1038,21 +1031,6 @@ public class GnssLocationProvider extends LocationProviderInterface } } - /** - * Disables this provider. When disabled, calls to getStatus() - * need not be handled. Hardware may be shut - * down while the provider is disabled. - */ - @Override - public void disable() { - synchronized (mLock) { - if (!mEnabled) return; - mEnabled = false; - } - - sendMessage(ENABLE, 0, null); - } - private void handleDisable() { if (DEBUG) Log.d(TAG, "handleDisable"); @@ -1069,7 +1047,6 @@ public class GnssLocationProvider extends LocationProviderInterface mGnssNavigationMessageProvider.onGpsEnabledChanged(); } - @Override public boolean isEnabled() { synchronized (mLock) { return mEnabled; @@ -1133,7 +1110,7 @@ public class GnssLocationProvider extends LocationProviderInterface updateClientUids(mWorkSource); mFixInterval = (int) mProviderRequest.interval; - mLowPowerMode = (boolean) mProviderRequest.lowPowerMode; + mLowPowerMode = mProviderRequest.lowPowerMode; // check for overflow if (mFixInterval != mProviderRequest.interval) { Log.w(TAG, "interval overflow: " + mProviderRequest.interval); @@ -1157,7 +1134,8 @@ public class GnssLocationProvider extends LocationProviderInterface // set timer to give up if we do not receive a fix within NO_FIX_TIMEOUT // and our fix interval is not short mAlarmManager.set(AlarmManager.ELAPSED_REALTIME_WAKEUP, - SystemClock.elapsedRealtime() + NO_FIX_TIMEOUT, mTimeoutIntent); } + SystemClock.elapsedRealtime() + NO_FIX_TIMEOUT, mTimeoutIntent); + } } } else { updateClientUids(new WorkSource()); @@ -1206,16 +1184,14 @@ public class GnssLocationProvider extends LocationProviderInterface List<WorkChain> goneChains = diffs[1]; if (newChains != null) { - for (int i = 0; i < newChains.size(); ++i) { - final WorkChain newChain = newChains.get(i); + for (WorkChain newChain : newChains) { mAppOps.startOpNoThrow(AppOpsManager.OP_GPS, newChain.getAttributionUid(), newChain.getAttributionTag()); } } if (goneChains != null) { - for (int i = 0; i < goneChains.size(); i++) { - final WorkChain goneChain = goneChains.get(i); + for (WorkChain goneChain : goneChains) { mAppOps.finishOp(AppOpsManager.OP_GPS, goneChain.getAttributionUid(), goneChain.getAttributionTag()); } @@ -1248,32 +1224,27 @@ public class GnssLocationProvider extends LocationProviderInterface } @Override - public boolean sendExtraCommand(String command, Bundle extras) { + public void sendExtraCommand(String command, Bundle extras) { long identity = Binder.clearCallingIdentity(); try { - boolean result = false; - if ("delete_aiding_data".equals(command)) { - result = deleteAidingData(extras); + deleteAidingData(extras); } else if ("force_time_injection".equals(command)) { requestUtcTime(); - result = true; } else if ("force_xtra_injection".equals(command)) { if (mSupportsXtra) { xtraDownloadRequest(); - result = true; } } else { Log.w(TAG, "sendExtraCommand: unknown command " + command); } - return result; } finally { Binder.restoreCallingIdentity(identity); } } - private boolean deleteAidingData(Bundle extras) { + private void deleteAidingData(Bundle extras) { int flags; if (extras == null) { @@ -1297,10 +1268,7 @@ public class GnssLocationProvider extends LocationProviderInterface if (flags != 0) { native_delete_aiding_data(flags); - return true; } - - return false; } private void startNavigating(boolean singleShot) { @@ -1344,7 +1312,7 @@ public class GnssLocationProvider extends LocationProviderInterface } int interval = (hasCapability(GPS_CAPABILITY_SCHEDULING) ? mFixInterval : 1000); - mLowPowerMode = (boolean) mProviderRequest.lowPowerMode; + mLowPowerMode = mProviderRequest.lowPowerMode; if (!setPositionMode(mPositionMode, GPS_POSITION_RECURRENCE_PERIODIC, interval, 0, 0, mLowPowerMode)) { mStarted = false; @@ -1401,10 +1369,7 @@ public class GnssLocationProvider extends LocationProviderInterface return ((mEngineCapabilities & capability) != 0); } - - /** - * called from native code to update our position. - */ + @NativeEntryPoint private void reportLocation(boolean hasLatLong, Location location) { sendMessage(REPORT_LOCATION, hasLatLong ? 1 : 0, location); } @@ -1430,11 +1395,7 @@ public class GnssLocationProvider extends LocationProviderInterface location.setElapsedRealtimeNanos(SystemClock.elapsedRealtimeNanos()); location.setExtras(mLocationExtras.getBundle()); - try { - mILocationManager.reportLocation(location, false); - } catch (RemoteException e) { - Log.e(TAG, "RemoteException calling reportLocation"); - } + reportLocation(location); if (mStarted) { mGnssMetrics.logReceivedLocationStatus(hasLatLong); @@ -1468,7 +1429,8 @@ public class GnssLocationProvider extends LocationProviderInterface if (mStarted && mStatus != LocationProvider.AVAILABLE) { // For devices that use framework scheduling, a timer may be set to ensure we don't - // spend too much power searching for a location, when the requested update rate is slow. + // spend too much power searching for a location, when the requested update rate is + // slow. // As we just recievied a location, we'll cancel that timer. if (!hasCapability(GPS_CAPABILITY_SCHEDULING) && mFixInterval < NO_FIX_TIMEOUT) { mAlarmManager.cancel(mTimeoutIntent); @@ -1488,9 +1450,7 @@ public class GnssLocationProvider extends LocationProviderInterface } } - /** - * called from native code to update our status - */ + @NativeEntryPoint private void reportStatus(int status) { if (DEBUG) Log.v(TAG, "reportStatus status: " + status); @@ -1498,16 +1458,13 @@ public class GnssLocationProvider extends LocationProviderInterface switch (status) { case GPS_STATUS_SESSION_BEGIN: mNavigating = true; - mEngineOn = true; break; case GPS_STATUS_SESSION_END: mNavigating = false; break; case GPS_STATUS_ENGINE_ON: - mEngineOn = true; break; case GPS_STATUS_ENGINE_OFF: - mEngineOn = false; mNavigating = false; break; } @@ -1524,17 +1481,15 @@ public class GnssLocationProvider extends LocationProviderInterface // Helper class to carry data to handler for reportSvStatus private static class SvStatusInfo { - public int mSvCount; - public int[] mSvidWithFlags; - public float[] mCn0s; - public float[] mSvElevations; - public float[] mSvAzimuths; - public float[] mSvCarrierFreqs; + private int mSvCount; + private int[] mSvidWithFlags; + private float[] mCn0s; + private float[] mSvElevations; + private float[] mSvAzimuths; + private float[] mSvCarrierFreqs; } - /** - * called from native code to update SV info - */ + @NativeEntryPoint private void reportSvStatus(int svCount, int[] svidWithFlags, float[] cn0s, float[] svElevations, float[] svAzimuths, float[] svCarrierFreqs) { SvStatusInfo svStatusInfo = new SvStatusInfo(); @@ -1608,16 +1563,12 @@ public class GnssLocationProvider extends LocationProviderInterface } } - /** - * called from native code to update AGPS status - */ + @NativeEntryPoint private void reportAGpsStatus(int type, int status, byte[] ipaddr) { mNetworkConnectivityHandler.onReportAGpsStatus(type, status, ipaddr); } - /** - * called from native code to report NMEA data received - */ + @NativeEntryPoint private void reportNmea(long timestamp) { if (!mItarSpeedLimitExceeded) { int length = native_read_nmea(mNmeaBuffer, mNmeaBuffer.length); @@ -1626,57 +1577,38 @@ public class GnssLocationProvider extends LocationProviderInterface } } - /** - * called from native code - GNSS measurements callback - */ + @NativeEntryPoint private void reportMeasurementData(GnssMeasurementsEvent event) { if (!mItarSpeedLimitExceeded) { // send to handler to allow native to return quickly - mHandler.post(new Runnable() { - @Override - public void run() { - mGnssMeasurementsProvider.onMeasurementsAvailable(event); - } - }); + mHandler.post(() -> mGnssMeasurementsProvider.onMeasurementsAvailable(event)); } } - /** - * called from native code - GNSS navigation message callback - */ + @NativeEntryPoint private void reportNavigationMessage(GnssNavigationMessage event) { if (!mItarSpeedLimitExceeded) { // send to handler to allow native to return quickly - mHandler.post(new Runnable() { - @Override - public void run() { - mGnssNavigationMessageProvider.onNavigationMessageAvailable(event); - } - }); + mHandler.post(() -> mGnssNavigationMessageProvider.onNavigationMessageAvailable(event)); } } - /** - * called from native code to inform us what the GPS engine capabilities are - */ + @NativeEntryPoint private void setEngineCapabilities(final int capabilities) { // send to handler thread for fast native return, and in-order handling - mHandler.post(new Runnable() { - @Override - public void run() { - mEngineCapabilities = capabilities; - - if (hasCapability(GPS_CAPABILITY_ON_DEMAND_TIME)) { - mNtpTimeHelper.enablePeriodicTimeInjection(); - requestUtcTime(); - } + mHandler.post(() -> { + mEngineCapabilities = capabilities; - mGnssMeasurementsProvider.onCapabilitiesUpdated(hasCapability( - GPS_CAPABILITY_MEASUREMENTS)); - mGnssNavigationMessageProvider.onCapabilitiesUpdated(hasCapability( - GPS_CAPABILITY_NAV_MESSAGES)); - restartRequests(); + if (hasCapability(GPS_CAPABILITY_ON_DEMAND_TIME)) { + mNtpTimeHelper.enablePeriodicTimeInjection(); + requestUtcTime(); } + + mGnssMeasurementsProvider.onCapabilitiesUpdated(hasCapability( + GPS_CAPABILITY_MEASUREMENTS)); + mGnssNavigationMessageProvider.onCapabilitiesUpdated(hasCapability( + GPS_CAPABILITY_NAV_MESSAGES)); + restartRequests(); }); } @@ -1696,27 +1628,21 @@ public class GnssLocationProvider extends LocationProviderInterface updateRequirements(); } - /** - * Called from native code to inform us the hardware year. - */ + @NativeEntryPoint private void setGnssYearOfHardware(final int yearOfHardware) { // mHardwareYear is simply set here, to be read elsewhere, and is volatile for safe sync if (DEBUG) Log.d(TAG, "setGnssYearOfHardware called with " + yearOfHardware); mHardwareYear = yearOfHardware; } - /** - * Called from native code to inform us the hardware model name. - */ + @NativeEntryPoint private void setGnssHardwareModelName(final String modelName) { // mHardwareModelName is simply set here, to be read elsewhere, and volatile for safe sync if (DEBUG) Log.d(TAG, "setGnssModelName called with " + modelName); mHardwareModelName = modelName; } - /** - * Called from native code to inform us GNSS HAL service died. - */ + @NativeEntryPoint private void reportGnssServiceDied() { if (DEBUG) Log.d(TAG, "reportGnssServiceDied"); mHandler.post(() -> { @@ -1736,6 +1662,7 @@ public class GnssLocationProvider extends LocationProviderInterface * Returns the year of underlying GPS hardware. */ int getGnssYearOfHardware(); + /** * Returns the model name of underlying GPS hardware. */ @@ -1751,6 +1678,7 @@ public class GnssLocationProvider extends LocationProviderInterface public int getGnssYearOfHardware() { return mHardwareYear; } + @Override public String getGnssHardwareModelName() { return mHardwareModelName; @@ -1776,32 +1704,19 @@ public class GnssLocationProvider extends LocationProviderInterface * @hide */ public GnssMetricsProvider getGnssMetricsProvider() { - return new GnssMetricsProvider() { - @Override - public String getGnssMetricsAsProtoString() { - return mGnssMetrics.dumpGnssMetricsAsProtoString(); - } - }; + return () -> mGnssMetrics.dumpGnssMetricsAsProtoString(); } - /** - * called from native code - GNSS location batch callback - */ + @NativeEntryPoint private void reportLocationBatch(Location[] locationArray) { List<Location> locations = new ArrayList<>(Arrays.asList(locationArray)); if (DEBUG) { Log.d(TAG, "Location batch of size " + locationArray.length + " reported"); } - try { - mILocationManager.reportLocationBatch(locations); - } catch (RemoteException e) { - Log.e(TAG, "RemoteException calling reportLocationBatch"); - } + reportLocation(locations); } - /** - * called from native code to request XTRA data - */ + @NativeEntryPoint private void xtraDownloadRequest() { if (DEBUG) Log.d(TAG, "xtraDownloadRequest"); sendMessage(DOWNLOAD_XTRA_DATA, 0, null); @@ -1829,10 +1744,7 @@ public class GnssLocationProvider extends LocationProviderInterface } } - /** - * Called from native to report GPS Geofence transition - * All geofence callbacks are called on the same thread - */ + @NativeEntryPoint private void reportGeofenceTransition(int geofenceId, Location location, int transition, long transitionTimestamp) { mHandler.post(() -> { @@ -1850,9 +1762,7 @@ public class GnssLocationProvider extends LocationProviderInterface }); } - /** - * called from native code to report GPS status change. - */ + @NativeEntryPoint private void reportGeofenceStatus(int status, Location location) { mHandler.post(() -> { if (mGeofenceHardwareImpl == null) { @@ -1870,9 +1780,7 @@ public class GnssLocationProvider extends LocationProviderInterface }); } - /** - * called from native code - Geofence Add callback - */ + @NativeEntryPoint private void reportGeofenceAddStatus(int geofenceId, int status) { mHandler.post(() -> { if (mGeofenceHardwareImpl == null) { @@ -1882,9 +1790,7 @@ public class GnssLocationProvider extends LocationProviderInterface }); } - /** - * called from native code - Geofence Remove callback - */ + @NativeEntryPoint private void reportGeofenceRemoveStatus(int geofenceId, int status) { mHandler.post(() -> { if (mGeofenceHardwareImpl == null) { @@ -1894,9 +1800,7 @@ public class GnssLocationProvider extends LocationProviderInterface }); } - /** - * called from native code - Geofence Pause callback - */ + @NativeEntryPoint private void reportGeofencePauseStatus(int geofenceId, int status) { mHandler.post(() -> { if (mGeofenceHardwareImpl == null) { @@ -1906,9 +1810,7 @@ public class GnssLocationProvider extends LocationProviderInterface }); } - /** - * called from native code - Geofence Resume callback - */ + @NativeEntryPoint private void reportGeofenceResumeStatus(int geofenceId, int status) { mHandler.post(() -> { if (mGeofenceHardwareImpl == null) { @@ -1940,7 +1842,8 @@ public class GnssLocationProvider extends LocationProviderInterface return mNetInitiatedListener; } - // Called by JNI function to report an NI request. + /** Reports a NI notification. */ + @NativeEntryPoint public void reportNiNotification( int notificationId, int niType, @@ -1983,11 +1886,10 @@ public class GnssLocationProvider extends LocationProviderInterface } /** - * Called from native code to request set id info. * We should be careful about receiving null string from the TelephonyManager, * because sending null String to JNI function would cause a crash. */ - + @NativeEntryPoint private void requestSetID(int flags) { TelephonyManager phone = (TelephonyManager) mContext.getSystemService(Context.TELEPHONY_SERVICE); @@ -2016,9 +1918,7 @@ public class GnssLocationProvider extends LocationProviderInterface native_agps_set_id(type, data); } - /** - * Called from native code to request location info. - */ + @NativeEntryPoint private void requestLocation(boolean independentFromGnss) { if (DEBUG) { Log.d(TAG, "requestLocation. independentFromGnss: " + independentFromGnss); @@ -2026,17 +1926,13 @@ public class GnssLocationProvider extends LocationProviderInterface sendMessage(REQUEST_LOCATION, 0, independentFromGnss); } - /** - * Called from native code to request utc time info - */ + @NativeEntryPoint private void requestUtcTime() { if (DEBUG) Log.d(TAG, "utcTimeRequest"); sendMessage(INJECT_NTP_TIME, 0, null); } - /** - * Called from native code to request reference location info - */ + @NativeEntryPoint private void requestRefLocation() { TelephonyManager phone = (TelephonyManager) mContext.getSystemService(Context.TELEPHONY_SERVICE); @@ -2090,11 +1986,7 @@ public class GnssLocationProvider extends LocationProviderInterface int message = msg.what; switch (message) { case ENABLE: - if (msg.arg1 == 1) { - handleEnable(); - } else { - handleDisable(); - } + handleEnable(); break; case SET_REQUEST: GpsRequest gpsRequest = (GpsRequest) msg.obj; @@ -2139,7 +2031,8 @@ public class GnssLocationProvider extends LocationProviderInterface } /** - * This method is bound to {@link #GnssLocationProvider(Context, ILocationManager, Looper)}. + * This method is bound to {@link #GnssLocationProvider(Context, LocationProviderManager, + * Looper)}. * It is in charge of loading properties and registering for events that will be posted to * this handler. */ @@ -2192,12 +2085,11 @@ public class GnssLocationProvider extends LocationProviderInterface (LocationManager) mContext.getSystemService(Context.LOCATION_SERVICE); long minTime = 0; float minDistance = 0; - boolean oneShot = false; LocationRequest request = LocationRequest.createFromDeprecatedProvider( LocationManager.PASSIVE_PROVIDER, minTime, minDistance, - oneShot); + false); // Don't keep track of this request since it's done on behalf of other clients // (which are kept track of separately). request.setHideFromAppOps(true); @@ -2205,11 +2097,14 @@ public class GnssLocationProvider extends LocationProviderInterface request, new NetworkLocationListener(), getLooper()); + + // enable gps provider, it will never be disabled (legacy behavior) + sendEmptyMessage(ENABLE); } } private abstract class LocationChangeListener implements LocationListener { - int numLocationUpdateRequest; + private int mNumLocationUpdateRequest; @Override public void onStatusChanged(String provider, int status, Bundle extras) { diff --git a/services/core/java/com/android/server/location/LocationProviderInterface.java b/services/core/java/com/android/server/location/LocationProviderInterface.java deleted file mode 100644 index 678596445fe3..000000000000 --- a/services/core/java/com/android/server/location/LocationProviderInterface.java +++ /dev/null @@ -1,78 +0,0 @@ -/* - * Copyright (C) 2010 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.android.server.location; - -import android.location.LocationProvider; -import android.os.Bundle; -import android.os.WorkSource; - -import com.android.internal.location.ProviderProperties; -import com.android.internal.location.ProviderRequest; - -import java.io.FileDescriptor; -import java.io.PrintWriter; - -/** - * Location Manager's interface for location providers. - * @hide - */ -public abstract class LocationProviderInterface { - - /** Get name. */ - public abstract String getName(); - - /** Enable. */ - public abstract void enable(); - - /** Disable. */ - public abstract void disable(); - - /** Is enabled. */ - public abstract boolean isEnabled(); - - /** Set request. */ - public abstract void setRequest(ProviderRequest request, WorkSource source); - - /** dump. */ - public abstract void dump(FileDescriptor fd, PrintWriter pw, String[] args); - - /** Get properties. */ - public abstract ProviderProperties getProperties(); - - /** - * Get status. - * - * @deprecated Will be removed in a future release. - */ - @Deprecated - public int getStatus(Bundle extras) { - return LocationProvider.AVAILABLE; - } - - /** - * Get status update time. - * - * @deprecated Will be removed in a future release. - */ - @Deprecated - public long getStatusUpdateTime() { - return 0; - } - - /** Send extra command. */ - public abstract boolean sendExtraCommand(String command, Bundle extras); -} diff --git a/services/core/java/com/android/server/location/LocationProviderProxy.java b/services/core/java/com/android/server/location/LocationProviderProxy.java index b40841467946..dfcef70c8248 100644 --- a/services/core/java/com/android/server/location/LocationProviderProxy.java +++ b/services/core/java/com/android/server/location/LocationProviderProxy.java @@ -18,6 +18,7 @@ package com.android.server.location; import android.annotation.Nullable; import android.content.Context; +import android.location.Location; import android.location.LocationProvider; import android.os.Bundle; import android.os.IBinder; @@ -27,6 +28,7 @@ import android.util.Log; import com.android.internal.annotations.GuardedBy; import com.android.internal.location.ILocationProvider; +import com.android.internal.location.ILocationProviderManager; import com.android.internal.location.ProviderProperties; import com.android.internal.location.ProviderRequest; import com.android.internal.os.BackgroundThread; @@ -41,21 +43,35 @@ import java.io.PrintWriter; /** * Proxy for ILocationProvider implementations. */ -public class LocationProviderProxy extends LocationProviderInterface { +public class LocationProviderProxy extends AbstractLocationProvider { + private static final String TAG = "LocationProviderProxy"; private static final boolean D = LocationManagerService.D; - private final ServiceWatcher mServiceWatcher; - - private final String mName; - // used to ensure that updates to mRequest and mWorkSource are atomic private final Object mRequestLock = new Object(); + private final ServiceWatcher mServiceWatcher; - private volatile boolean mEnabled = false; - @Nullable - private volatile ProviderProperties mProperties; + private final ILocationProviderManager.Stub mManager = new ILocationProviderManager.Stub() { + // executed on binder thread + @Override + public void onSetEnabled(boolean enabled) { + LocationProviderProxy.this.setEnabled(enabled); + } + + // executed on binder thread + @Override + public void onSetProperties(ProviderProperties properties) { + LocationProviderProxy.this.setProperties(properties); + } + + // executed on binder thread + @Override + public void onReportLocation(Location location) { + LocationProviderProxy.this.reportLocation(location); + } + }; @GuardedBy("mRequestLock") @Nullable @@ -69,10 +85,10 @@ public class LocationProviderProxy extends LocationProviderInterface { */ @Nullable public static LocationProviderProxy createAndBind( - Context context, String name, String action, + Context context, LocationProviderManager locationProviderManager, String action, int overlaySwitchResId, int defaultServicePackageNameResId, int initialPackageNamesResId) { - LocationProviderProxy proxy = new LocationProviderProxy(context, name, + LocationProviderProxy proxy = new LocationProviderProxy(context, locationProviderManager, action, overlaySwitchResId, defaultServicePackageNameResId, initialPackageNamesResId); if (proxy.bind()) { @@ -82,21 +98,27 @@ public class LocationProviderProxy extends LocationProviderInterface { } } - private LocationProviderProxy(Context context, String name, + private LocationProviderProxy(Context context, LocationProviderManager locationProviderManager, String action, int overlaySwitchResId, int defaultServicePackageNameResId, int initialPackageNamesResId) { + super(locationProviderManager, false); mServiceWatcher = new ServiceWatcher(context, TAG, action, overlaySwitchResId, defaultServicePackageNameResId, initialPackageNamesResId, BackgroundThread.getHandler()) { + @Override protected void onBind() { runOnBinder(LocationProviderProxy.this::initializeService); } + + @Override + protected void onUnbind() { + setEnabled(false); + setProperties(null); + } }; - mName = name; - mProperties = null; mRequest = null; mWorkSource = new WorkSource(); } @@ -107,84 +129,27 @@ public class LocationProviderProxy extends LocationProviderInterface { private void initializeService(IBinder binder) { ILocationProvider service = ILocationProvider.Stub.asInterface(binder); - if (D) Log.d(TAG, "applying state to connected service"); - - ProviderProperties[] properties = new ProviderProperties[1]; - ProviderRequest request; - WorkSource source; - synchronized (mRequestLock) { - request = mRequest; - source = mWorkSource; - } + if (D) Log.d(TAG, "applying state to connected service " + mServiceWatcher); try { - // load properties from provider - properties[0] = service.getProperties(); - if (properties[0] == null) { - Log.e(TAG, mServiceWatcher.getCurrentPackageName() - + " has invalid location provider properties"); - } + service.setLocationProviderManager(mManager); - // apply current state to new service - if (mEnabled) { - service.enable(); - if (request != null) { - service.setRequest(request, source); + synchronized (mRequestLock) { + if (mRequest != null) { + service.setRequest(mRequest, mWorkSource); } } } catch (RemoteException e) { Log.w(TAG, e); } - - mProperties = properties[0]; } + @Nullable public String getConnectedPackageName() { return mServiceWatcher.getCurrentPackageName(); } @Override - public String getName() { - return mName; - } - - @Override - public ProviderProperties getProperties() { - return mProperties; - } - - @Override - public void enable() { - mEnabled = true; - mServiceWatcher.runOnBinder(binder -> { - ILocationProvider service = ILocationProvider.Stub.asInterface(binder); - try { - service.enable(); - } catch (RemoteException e) { - Log.w(TAG, e); - } - }); - } - - @Override - public void disable() { - mEnabled = false; - mServiceWatcher.runOnBinder(binder -> { - ILocationProvider service = ILocationProvider.Stub.asInterface(binder); - try { - service.disable(); - } catch (RemoteException e) { - Log.w(TAG, e); - } - }); - } - - @Override - public boolean isEnabled() { - return mEnabled; - } - - @Override public void setRequest(ProviderRequest request, WorkSource source) { synchronized (mRequestLock) { mRequest = request; @@ -202,60 +167,53 @@ public class LocationProviderProxy extends LocationProviderInterface { @Override public void dump(FileDescriptor fd, PrintWriter pw, String[] args) { - pw.append("REMOTE SERVICE"); - pw.append(" name=").append(mName); - pw.append(" pkg=").append(mServiceWatcher.getCurrentPackageName()); - pw.append(" version=").append(Integer.toString(mServiceWatcher.getCurrentPackageVersion())); - pw.append('\n'); + pw.println(" service=" + mServiceWatcher); mServiceWatcher.runOnBinder(binder -> { - ILocationProvider service = ILocationProvider.Stub.asInterface(binder); try { - TransferPipe.dumpAsync(service.asBinder(), fd, args); + TransferPipe.dumpAsync(binder, fd, args); } catch (IOException | RemoteException e) { - pw.println("Failed to dump location provider: " + e); + pw.println(" failed to dump location provider: " + e); } }); } @Override public int getStatus(Bundle extras) { - int[] result = new int[]{LocationProvider.TEMPORARILY_UNAVAILABLE}; + int[] status = new int[] {LocationProvider.TEMPORARILY_UNAVAILABLE}; mServiceWatcher.runOnBinder(binder -> { ILocationProvider service = ILocationProvider.Stub.asInterface(binder); try { - result[0] = service.getStatus(extras); + status[0] = service.getStatus(extras); } catch (RemoteException e) { Log.w(TAG, e); } }); - return result[0]; + return status[0]; } @Override public long getStatusUpdateTime() { - long[] result = new long[]{0L}; + long[] updateTime = new long[] {0L}; mServiceWatcher.runOnBinder(binder -> { ILocationProvider service = ILocationProvider.Stub.asInterface(binder); try { - result[0] = service.getStatusUpdateTime(); + updateTime[0] = service.getStatusUpdateTime(); } catch (RemoteException e) { Log.w(TAG, e); } }); - return result[0]; + return updateTime[0]; } @Override - public boolean sendExtraCommand(String command, Bundle extras) { - boolean[] result = new boolean[]{false}; + public void sendExtraCommand(String command, Bundle extras) { mServiceWatcher.runOnBinder(binder -> { ILocationProvider service = ILocationProvider.Stub.asInterface(binder); try { - result[0] = service.sendExtraCommand(command, extras); + service.sendExtraCommand(command, extras); } catch (RemoteException e) { Log.w(TAG, e); } }); - return result[0]; } } diff --git a/services/core/java/com/android/server/location/MockProvider.java b/services/core/java/com/android/server/location/MockProvider.java index 145aee3a9e6a..bfbebf74e93d 100644 --- a/services/core/java/com/android/server/location/MockProvider.java +++ b/services/core/java/com/android/server/location/MockProvider.java @@ -16,14 +16,11 @@ package com.android.server.location; -import android.location.ILocationManager; +import android.annotation.Nullable; import android.location.Location; import android.location.LocationProvider; import android.os.Bundle; -import android.os.RemoteException; import android.os.WorkSource; -import android.util.Log; -import android.util.PrintWriterPrinter; import com.android.internal.location.ProviderProperties; import com.android.internal.location.ProviderRequest; @@ -36,61 +33,55 @@ import java.io.PrintWriter; * * {@hide} */ -public class MockProvider extends LocationProviderInterface { - private final String mName; - private final ProviderProperties mProperties; - private final ILocationManager mLocationManager; +public class MockProvider extends AbstractLocationProvider { - private final Location mLocation; - - private boolean mHasLocation; private boolean mEnabled; - - + @Nullable private Location mLocation; private int mStatus; private long mStatusUpdateTime; private Bundle mExtras; - private static final String TAG = "MockProvider"; - - public MockProvider(String name, ILocationManager locationManager, - ProviderProperties properties) { - if (properties == null) throw new NullPointerException("properties is null"); - - mName = name; - mLocationManager = locationManager; - mProperties = properties; - mLocation = new Location(name); + public MockProvider( + LocationProviderManager locationProviderManager, ProviderProperties properties) { + super(locationProviderManager, true); + mEnabled = true; + mLocation = null; mStatus = LocationProvider.AVAILABLE; - mStatusUpdateTime = 0L; + mStatusUpdateTime = 0; mExtras = null; + + setProperties(properties); } - @Override - public String getName() { - return mName; + /** Sets the enabled state of this mock provider. */ + public void setEnabled(boolean enabled) { + mEnabled = enabled; + super.setEnabled(enabled); } - @Override - public ProviderProperties getProperties() { - return mProperties; + /** Sets the location to report for this mock provider. */ + public void setLocation(Location l) { + mLocation = new Location(l); + if (mEnabled) { + reportLocation(l); + } } - @Override - public void disable() { - mEnabled = false; + /** Sets the status for this mock provider. */ + public void setStatus(int status, Bundle extras, long updateTime) { + mStatus = status; + mStatusUpdateTime = updateTime; + mExtras = extras; } @Override - public void enable() { - mEnabled = true; + public void dump(FileDescriptor fd, PrintWriter pw, String[] args) { + pw.println(" last location=" + mLocation); } @Override - public boolean isEnabled() { - return mEnabled; - } + public void setRequest(ProviderRequest request, WorkSource source) {} @Override public int getStatus(Bundle extras) { @@ -107,50 +98,6 @@ public class MockProvider extends LocationProviderInterface { return mStatusUpdateTime; } - public void setLocation(Location l) { - mLocation.set(l); - mHasLocation = true; - if (mEnabled) { - try { - mLocationManager.reportLocation(mLocation, false); - } catch (RemoteException e) { - Log.e(TAG, "RemoteException calling reportLocation"); - } - } - } - - public void clearLocation() { - mHasLocation = false; - } - - /** - * @deprecated Will be removed in a future release. - */ - @Deprecated - public void setStatus(int status, Bundle extras, long updateTime) { - mStatus = status; - mStatusUpdateTime = updateTime; - mExtras = extras; - } - - @Override - public void dump(FileDescriptor fd, PrintWriter pw, String[] args) { - dump(pw, ""); - } - - public void dump(PrintWriter pw, String prefix) { - pw.println(prefix + mName); - pw.println(prefix + "mHasLocation=" + mHasLocation); - pw.println(prefix + "mLocation:"); - mLocation.dump(new PrintWriterPrinter(pw), prefix + " "); - pw.println(prefix + "mExtras=" + mExtras); - } - @Override - public void setRequest(ProviderRequest request, WorkSource source) { } - - @Override - public boolean sendExtraCommand(String command, Bundle extras) { - return false; - } + public void sendExtraCommand(String command, Bundle extras) {} } diff --git a/services/core/java/com/android/server/location/PassiveProvider.java b/services/core/java/com/android/server/location/PassiveProvider.java index 99c92149fa1b..70d64b02e4b4 100644 --- a/services/core/java/com/android/server/location/PassiveProvider.java +++ b/services/core/java/com/android/server/location/PassiveProvider.java @@ -17,13 +17,9 @@ package com.android.server.location; import android.location.Criteria; -import android.location.ILocationManager; import android.location.Location; -import android.location.LocationManager; import android.os.Bundle; -import android.os.RemoteException; import android.os.WorkSource; -import android.util.Log; import com.android.internal.location.ProviderProperties; import com.android.internal.location.ProviderRequest; @@ -38,41 +34,20 @@ import java.io.PrintWriter; * * {@hide} */ -public class PassiveProvider extends LocationProviderInterface { - private static final String TAG = "PassiveProvider"; +public class PassiveProvider extends AbstractLocationProvider { private static final ProviderProperties PROPERTIES = new ProviderProperties( false, false, false, false, false, false, false, Criteria.POWER_LOW, Criteria.ACCURACY_COARSE); - private final ILocationManager mLocationManager; private boolean mReportLocation; - public PassiveProvider(ILocationManager locationManager) { - mLocationManager = locationManager; - } - - @Override - public String getName() { - return LocationManager.PASSIVE_PROVIDER; - } - - @Override - public ProviderProperties getProperties() { - return PROPERTIES; - } + public PassiveProvider(LocationProviderManager locationProviderManager) { + super(locationProviderManager, true); - @Override - public boolean isEnabled() { - return true; - } + mReportLocation = false; - @Override - public void enable() { - } - - @Override - public void disable() { + setProperties(PROPERTIES); } @Override @@ -82,22 +57,15 @@ public class PassiveProvider extends LocationProviderInterface { public void updateLocation(Location location) { if (mReportLocation) { - try { - // pass the location back to the location manager - mLocationManager.reportLocation(location, true); - } catch (RemoteException e) { - Log.e(TAG, "RemoteException calling reportLocation"); - } + reportLocation(location); } } @Override - public boolean sendExtraCommand(String command, Bundle extras) { - return false; - } + public void sendExtraCommand(String command, Bundle extras) {} @Override public void dump(FileDescriptor fd, PrintWriter pw, String[] args) { - pw.println("mReportLocation=" + mReportLocation); + pw.println(" report location=" + mReportLocation); } } diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java index b12d4b6b504e..888675c117e1 100644 --- a/services/core/java/com/android/server/pm/PackageManagerService.java +++ b/services/core/java/com/android/server/pm/PackageManagerService.java @@ -1301,6 +1301,7 @@ public class PackageManagerService extends IPackageManager.Stub final @Nullable String mSetupWizardPackage; final @Nullable String mStorageManagerPackage; final @Nullable String mSystemTextClassifierPackage; + final @Nullable String mWellbeingPackage; final @NonNull String mServicesSystemSharedLibraryPackageName; final @NonNull String mSharedSystemSharedLibraryPackageName; @@ -2790,6 +2791,8 @@ public class PackageManagerService extends IPackageManager.Stub mSystemTextClassifierPackage = getSystemTextClassifierPackageName(); + mWellbeingPackage = getWellbeingPackageName(); + // Now that we know all of the shared libraries, update all clients to have // the correct library paths. updateAllSharedLibrariesLPw(null); @@ -18307,6 +18310,10 @@ public class PackageManagerService extends IPackageManager.Stub continue; } + if (bp.isRemoved()) { + continue; + } + // If shared user we just reset the state to which only this app contributed. if (ps.sharedUser != null) { boolean used = false; @@ -19564,6 +19571,11 @@ public class PackageManagerService extends IPackageManager.Stub } @Override + public String getWellbeingPackageName() { + return mContext.getString(R.string.config_defaultWellbeingPackage); + } + + @Override public void setApplicationEnabledSetting(String appPackageName, int newState, int flags, int userId, String callingPackage) { if (!sUserManager.exists(userId)) return; @@ -22719,6 +22731,8 @@ public class PackageManagerService extends IPackageManager.Stub return mSystemTextClassifierPackage; case PackageManagerInternal.PACKAGE_PERMISSION_CONTROLLER: return mRequiredPermissionControllerPackage; + case PackageManagerInternal.PACKAGE_WELLBEING: + return mWellbeingPackage; } return null; } diff --git a/services/core/java/com/android/server/pm/permission/BasePermission.java b/services/core/java/com/android/server/pm/permission/BasePermission.java index 2d583ca39adb..996f42b64664 100644 --- a/services/core/java/com/android/server/pm/permission/BasePermission.java +++ b/services/core/java/com/android/server/pm/permission/BasePermission.java @@ -189,6 +189,11 @@ public final class BasePermission { return (protectionLevel & PermissionInfo.PROTECTION_MASK_BASE) == PermissionInfo.PROTECTION_DANGEROUS; } + + public boolean isRemoved() { + return perm.info != null && (perm.info.flags & PermissionInfo.FLAG_REMOVED) != 0; + } + public boolean isSignature() { return (protectionLevel & PermissionInfo.PROTECTION_MASK_BASE) == PermissionInfo.PROTECTION_SIGNATURE; @@ -235,6 +240,9 @@ public final class BasePermission { return (protectionLevel & PermissionInfo.PROTECTION_FLAG_SYSTEM_TEXT_CLASSIFIER) != 0; } + public boolean isWellbeing() { + return (protectionLevel & PermissionInfo.PROTECTION_FLAG_WELLBEING) != 0; + } public void transfer(@NonNull String origPackageName, @NonNull String newPackageName) { if (!origPackageName.equals(sourcePackageName)) { diff --git a/services/core/java/com/android/server/pm/permission/PermissionManagerService.java b/services/core/java/com/android/server/pm/permission/PermissionManagerService.java index 4406fdde6454..bc3c18d9d49c 100644 --- a/services/core/java/com/android/server/pm/permission/PermissionManagerService.java +++ b/services/core/java/com/android/server/pm/permission/PermissionManagerService.java @@ -799,6 +799,10 @@ public class PermissionManagerService { continue; } + if (bp.isRemoved()) { + continue; + } + // Limit ephemeral apps to ephemeral allowed permissions. if (pkg.applicationInfo.isInstantApp() && !bp.isInstant()) { if (DEBUG_PERMISSIONS) { @@ -1637,6 +1641,12 @@ public class PermissionManagerService { // Special permissions for the system default text classifier. allowed = true; } + if (!allowed && bp.isWellbeing() + && pkg.packageName.equals(mPackageManagerInt.getKnownPackageName( + PackageManagerInternal.PACKAGE_WELLBEING, UserHandle.USER_SYSTEM))) { + // Special permission granted only to the OEM specified wellbeing app + allowed = true; + } } return allowed; } diff --git a/services/core/java/com/android/server/textclassifier/TextClassificationManagerService.java b/services/core/java/com/android/server/textclassifier/TextClassificationManagerService.java index c8a68b44c796..6b0419e0f7ad 100644 --- a/services/core/java/com/android/server/textclassifier/TextClassificationManagerService.java +++ b/services/core/java/com/android/server/textclassifier/TextClassificationManagerService.java @@ -23,7 +23,6 @@ import android.content.ComponentName; import android.content.Context; import android.content.Intent; import android.content.ServiceConnection; -import android.content.pm.PackageManager; import android.os.Binder; import android.os.IBinder; import android.os.RemoteException; @@ -136,6 +135,7 @@ public final class TextClassificationManagerService extends ITextClassifierServi throws RemoteException { Preconditions.checkNotNull(request); Preconditions.checkNotNull(callback); + validateInput(mContext, request.getCallingPackageName()); synchronized (mLock) { UserState userState = getCallingUserStateLocked(); @@ -158,6 +158,7 @@ public final class TextClassificationManagerService extends ITextClassifierServi throws RemoteException { Preconditions.checkNotNull(request); Preconditions.checkNotNull(callback); + validateInput(mContext, request.getCallingPackageName()); synchronized (mLock) { UserState userState = getCallingUserStateLocked(); @@ -180,6 +181,7 @@ public final class TextClassificationManagerService extends ITextClassifierServi throws RemoteException { Preconditions.checkNotNull(request); Preconditions.checkNotNull(callback); + validateInput(mContext, request.getCallingPackageName()); synchronized (mLock) { UserState userState = getCallingUserStateLocked(); @@ -199,7 +201,7 @@ public final class TextClassificationManagerService extends ITextClassifierServi public void onSelectionEvent( TextClassificationSessionId sessionId, SelectionEvent event) throws RemoteException { Preconditions.checkNotNull(event); - validateInput(event.getPackageName(), mContext); + validateInput(mContext, event.getPackageName()); synchronized (mLock) { UserState userState = getCallingUserStateLocked(); @@ -220,6 +222,7 @@ public final class TextClassificationManagerService extends ITextClassifierServi ITextLanguageCallback callback) throws RemoteException { Preconditions.checkNotNull(request); Preconditions.checkNotNull(callback); + validateInput(mContext, request.getCallingPackageName()); synchronized (mLock) { UserState userState = getCallingUserStateLocked(); @@ -242,6 +245,7 @@ public final class TextClassificationManagerService extends ITextClassifierServi IConversationActionsCallback callback) throws RemoteException { Preconditions.checkNotNull(request); Preconditions.checkNotNull(callback); + validateInput(mContext, request.getCallingPackageName()); synchronized (mLock) { UserState userState = getCallingUserStateLocked(); @@ -263,7 +267,7 @@ public final class TextClassificationManagerService extends ITextClassifierServi throws RemoteException { Preconditions.checkNotNull(sessionId); Preconditions.checkNotNull(classificationContext); - validateInput(classificationContext.getPackageName(), mContext); + validateInput(mContext, classificationContext.getPackageName()); synchronized (mLock) { UserState userState = getCallingUserStateLocked(); @@ -398,15 +402,17 @@ public final class TextClassificationManagerService extends ITextClassifierServi e -> Slog.d(LOG_TAG, "Error " + opDesc + ": " + e.getMessage())); } - private static void validateInput(String packageName, Context context) + private static void validateInput(Context context, @Nullable String packageName) throws RemoteException { + if (packageName == null) return; + try { final int uid = context.getPackageManager() .getPackageUidAsUser(packageName, UserHandle.getCallingUserId()); Preconditions.checkArgument(Binder.getCallingUid() == uid); - } catch (IllegalArgumentException | NullPointerException | - PackageManager.NameNotFoundException e) { - throw new RemoteException(e.getMessage()); + } catch (Exception e) { + throw new RemoteException( + String.format("Invalid package: name=%s, error=%s", packageName, e)); } } diff --git a/services/java/com/android/server/SystemServer.java b/services/java/com/android/server/SystemServer.java index 2baef6af0c11..88f645defa6d 100644 --- a/services/java/com/android/server/SystemServer.java +++ b/services/java/com/android/server/SystemServer.java @@ -36,7 +36,6 @@ import android.content.res.Configuration; import android.content.res.Resources.Theme; import android.database.sqlite.SQLiteCompatibilityWalFlags; import android.database.sqlite.SQLiteGlobal; -import android.hardware.display.ColorDisplayManager; import android.os.BaseBundle; import android.os.Binder; import android.os.Build; @@ -1443,11 +1442,9 @@ public final class SystemServer { mSystemServiceManager.startService(TwilightService.class); traceEnd(); - if (ColorDisplayManager.isNightDisplayAvailable(context)) { - traceBeginAndSlog("StartColorDisplay"); - mSystemServiceManager.startService(ColorDisplayService.class); - traceEnd(); - } + traceBeginAndSlog("StartColorDisplay"); + mSystemServiceManager.startService(ColorDisplayService.class); + traceEnd(); traceBeginAndSlog("StartJobScheduler"); mSystemServiceManager.startService(JobSchedulerService.class); diff --git a/telephony/java/android/telephony/CarrierConfigManager.java b/telephony/java/android/telephony/CarrierConfigManager.java index 0a60e3409c9d..60eb18cacb88 100644 --- a/telephony/java/android/telephony/CarrierConfigManager.java +++ b/telephony/java/android/telephony/CarrierConfigManager.java @@ -78,6 +78,15 @@ public class CarrierConfigManager { // system image, that can be added in packages/apps/CarrierConfig. /** + * Specifies a value that identifies the version of the carrier configuration that is + * currently in use. This string is displayed on the UI. + * The format of the string is not specified. + * @hide + */ + public static final String KEY_CARRIER_CONFIG_VERSION_STRING = + "carrier_config_version_string"; + + /** * This flag specifies whether VoLTE availability is based on provisioning. By default this is * false. */ @@ -2392,6 +2401,7 @@ public class CarrierConfigManager { static { sDefaults = new PersistableBundle(); + sDefaults.putString(KEY_CARRIER_CONFIG_VERSION_STRING, ""); sDefaults.putBoolean(KEY_ALLOW_HOLD_IN_IMS_CALL_BOOL, true); sDefaults.putBoolean(KEY_CARRIER_ALLOW_DEFLECT_IMS_CALL_BOOL, false); sDefaults.putBoolean(KEY_ALWAYS_PLAY_REMOTE_HOLD_TONE_BOOL, false); diff --git a/telephony/java/android/telephony/PhoneNumberUtils.java b/telephony/java/android/telephony/PhoneNumberUtils.java index f6e8d3422eca..c95837e1e1de 100644 --- a/telephony/java/android/telephony/PhoneNumberUtils.java +++ b/telephony/java/android/telephony/PhoneNumberUtils.java @@ -1738,7 +1738,10 @@ public class PhoneNumberUtils { * @param number the number to look up. * @return true if the number is in the list of emergency numbers * listed in the RIL / SIM, otherwise return false. + * + * @deprecated Please use {@link TelephonyManager#isCurrentEmergencyNumber(String)} instead. */ + @Deprecated public static boolean isEmergencyNumber(String number) { return isEmergencyNumber(getDefaultVoiceSubId(), number); } @@ -1751,8 +1754,13 @@ public class PhoneNumberUtils { * @param number the number to look up. * @return true if the number is in the list of emergency numbers * listed in the RIL / SIM, otherwise return false. + * + * @deprecated Please use {@link TelephonyManager#isCurrentEmergencyNumber(String)} + * instead. + * * @hide */ + @Deprecated @UnsupportedAppUsage public static boolean isEmergencyNumber(int subId, String number) { // Return true only if the specified number *exactly* matches @@ -1778,8 +1786,12 @@ public class PhoneNumberUtils { * listed in the RIL / SIM, *or* if the number starts with the * same digits as any of those emergency numbers. * + * @deprecated Please use {@link TelephonyManager#isCurrentPotentialEmergencyNumber(String)} + * instead. + * * @hide */ + @Deprecated public static boolean isPotentialEmergencyNumber(String number) { return isPotentialEmergencyNumber(getDefaultVoiceSubId(), number); } @@ -1802,9 +1814,14 @@ public class PhoneNumberUtils { * @return true if the number is in the list of emergency numbers * listed in the RIL / SIM, *or* if the number starts with the * same digits as any of those emergency numbers. + * + * @deprecated Please use {@link TelephonyManager#isCurrentPotentialEmergencyNumber(String)} + * instead. + * * @hide */ @UnsupportedAppUsage + @Deprecated public static boolean isPotentialEmergencyNumber(int subId, String number) { // Check against the emergency numbers listed by the RIL / SIM, // and *don't* require an exact match. @@ -1867,8 +1884,12 @@ public class PhoneNumberUtils { * @return if the number is an emergency number for the specific country, then return true, * otherwise false * + * @deprecated Please use {@link TelephonyManager#isCurrentEmergencyNumber(String)} + * instead. + * * @hide */ + @Deprecated @UnsupportedAppUsage public static boolean isEmergencyNumber(String number, String defaultCountryIso) { return isEmergencyNumber(getDefaultVoiceSubId(), number, defaultCountryIso); @@ -1882,8 +1903,13 @@ public class PhoneNumberUtils { * @param defaultCountryIso the specific country which the number should be checked against * @return if the number is an emergency number for the specific country, then return true, * otherwise false + * + * @deprecated Please use {@link TelephonyManager#isCurrentEmergencyNumber(String)} + * instead. + * * @hide */ + @Deprecated public static boolean isEmergencyNumber(int subId, String number, String defaultCountryIso) { return isEmergencyNumberInternal(subId, number, defaultCountryIso, @@ -1909,8 +1935,12 @@ public class PhoneNumberUtils { * country, *or* if the number starts with the same digits as * any of those emergency numbers. * + * @deprecated Please use {@link TelephonyManager#isCurrentPotentialEmergencyNumber(String)} + * instead. + * * @hide */ + @Deprecated public static boolean isPotentialEmergencyNumber(String number, String defaultCountryIso) { return isPotentialEmergencyNumber(getDefaultVoiceSubId(), number, defaultCountryIso); } @@ -1934,8 +1964,13 @@ public class PhoneNumberUtils { * @return true if the number is an emergency number for the specific * country, *or* if the number starts with the same digits as * any of those emergency numbers. + * + * @deprecated Please use {@link TelephonyManager#isCurrentPotentialEmergencyNumber(String)} + * instead. + * * @hide */ + @Deprecated public static boolean isPotentialEmergencyNumber(int subId, String number, String defaultCountryIso) { return isEmergencyNumberInternal(subId, number, @@ -1983,92 +2018,7 @@ public class PhoneNumberUtils { private static boolean isEmergencyNumberInternal(int subId, String number, String defaultCountryIso, boolean useExactMatch) { - // If the number passed in is null, just return false: - if (number == null) return false; - - // If the number passed in is a SIP address, return false, since the - // concept of "emergency numbers" is only meaningful for calls placed - // over the cell network. - // (Be sure to do this check *before* calling extractNetworkPortionAlt(), - // since the whole point of extractNetworkPortionAlt() is to filter out - // any non-dialable characters (which would turn 'abc911def@example.com' - // into '911', for example.)) - if (isUriNumber(number)) { - return false; - } - - // Strip the separators from the number before comparing it - // to the list. - number = extractNetworkPortionAlt(number); - - String emergencyNumbers = ""; - int slotId = SubscriptionManager.getSlotIndex(subId); - - // retrieve the list of emergency numbers - // check read-write ecclist property first - String ecclist = (slotId <= 0) ? "ril.ecclist" : ("ril.ecclist" + slotId); - - emergencyNumbers = SystemProperties.get(ecclist, ""); - - Rlog.d(LOG_TAG, "slotId:" + slotId + " subId:" + subId + " country:" - + defaultCountryIso + " emergencyNumbers: " + emergencyNumbers); - - if (TextUtils.isEmpty(emergencyNumbers)) { - // then read-only ecclist property since old RIL only uses this - emergencyNumbers = SystemProperties.get("ro.ril.ecclist"); - } - - if (!TextUtils.isEmpty(emergencyNumbers)) { - // searches through the comma-separated list for a match, - // return true if one is found. - for (String emergencyNum : emergencyNumbers.split(",")) { - // It is not possible to append additional digits to an emergency number to dial - // the number in Brazil - it won't connect. - if (useExactMatch || "BR".equalsIgnoreCase(defaultCountryIso)) { - if (number.equals(emergencyNum)) { - return true; - } - } else { - if (number.startsWith(emergencyNum)) { - return true; - } - } - } - // no matches found against the list! - return false; - } - - Rlog.d(LOG_TAG, "System property doesn't provide any emergency numbers." - + " Use embedded logic for determining ones."); - - // If slot id is invalid, means that there is no sim card. - // According spec 3GPP TS22.101, the following numbers should be - // ECC numbers when SIM/USIM is not present. - emergencyNumbers = ((slotId < 0) ? "112,911,000,08,110,118,119,999" : "112,911"); - - for (String emergencyNum : emergencyNumbers.split(",")) { - if (useExactMatch) { - if (number.equals(emergencyNum)) { - return true; - } - } else { - if (number.startsWith(emergencyNum)) { - return true; - } - } - } - - // No ecclist system property, so use our own list. - if (defaultCountryIso != null) { - ShortNumberInfo info = ShortNumberInfo.getInstance(); - if (useExactMatch) { - return info.isEmergencyNumber(number, defaultCountryIso); - } else { - return info.connectsToEmergencyNumber(number, defaultCountryIso); - } - } - - return false; + return TelephonyManager.getDefault().isCurrentEmergencyNumber(number); } /** @@ -2078,7 +2028,11 @@ public class PhoneNumberUtils { * @param context the specific context which the number should be checked against * @return true if the specified number is an emergency number for the country the user * is currently in. + * + * @deprecated Please use {@link TelephonyManager#isCurrentEmergencyNumber(String)} + * instead. */ + @Deprecated public static boolean isLocalEmergencyNumber(Context context, String number) { return isLocalEmergencyNumber(context, getDefaultVoiceSubId(), number); } @@ -2091,8 +2045,13 @@ public class PhoneNumberUtils { * @param context the specific context which the number should be checked against * @return true if the specified number is an emergency number for the country the user * is currently in. + * + * @deprecated Please use {@link TelephonyManager#isCurrentEmergencyNumber(String)} + * instead. + * * @hide */ + @Deprecated @UnsupportedAppUsage public static boolean isLocalEmergencyNumber(Context context, int subId, String number) { return isLocalEmergencyNumberInternal(subId, number, @@ -2120,8 +2079,13 @@ public class PhoneNumberUtils { * CountryDetector. * * @see android.location.CountryDetector + * + * @deprecated Please use {@link TelephonyManager#isCurrentPotentialEmergencyNumber(String)} + * instead. + * * @hide */ + @Deprecated @UnsupportedAppUsage public static boolean isPotentialLocalEmergencyNumber(Context context, String number) { return isPotentialLocalEmergencyNumber(context, getDefaultVoiceSubId(), number); @@ -2147,9 +2111,13 @@ public class PhoneNumberUtils { * @return true if the specified number is an emergency number for a local country, based on the * CountryDetector. * + * @deprecated Please use {@link TelephonyManager#isCurrentPotentialEmergencyNumber(String)} + * instead. + * * @hide */ @UnsupportedAppUsage + @Deprecated public static boolean isPotentialLocalEmergencyNumber(Context context, int subId, String number) { return isLocalEmergencyNumberInternal(subId, number, @@ -2217,6 +2185,101 @@ public class PhoneNumberUtils { } /** + * Back-up old logics for {@link #isEmergencyNumberInternal} for legacy and deprecate purpose. + * + * @hide + */ + public static boolean isEmergencyNumberInternal(String number, boolean useExactMatch, + String defaultCountryIso) { + // If the number passed in is null, just return false: + if (number == null) return false; + + // If the number passed in is a SIP address, return false, since the + // concept of "emergency numbers" is only meaningful for calls placed + // over the cell network. + // (Be sure to do this check *before* calling extractNetworkPortionAlt(), + // since the whole point of extractNetworkPortionAlt() is to filter out + // any non-dialable characters (which would turn 'abc911def@example.com' + // into '911', for example.)) + if (PhoneNumberUtils.isUriNumber(number)) { + return false; + } + + // Strip the separators from the number before comparing it + // to the list. + number = PhoneNumberUtils.extractNetworkPortionAlt(number); + + String emergencyNumbers = ""; + int slotId = SubscriptionManager.getSlotIndex(getDefaultVoiceSubId()); + + // retrieve the list of emergency numbers + // check read-write ecclist property first + String ecclist = (slotId <= 0) ? "ril.ecclist" : ("ril.ecclist" + slotId); + + emergencyNumbers = SystemProperties.get(ecclist, ""); + + Rlog.d(LOG_TAG, "slotId:" + slotId + " country:" + + defaultCountryIso + " emergencyNumbers: " + emergencyNumbers); + + if (TextUtils.isEmpty(emergencyNumbers)) { + // then read-only ecclist property since old RIL only uses this + emergencyNumbers = SystemProperties.get("ro.ril.ecclist"); + } + + if (!TextUtils.isEmpty(emergencyNumbers)) { + // searches through the comma-separated list for a match, + // return true if one is found. + for (String emergencyNum : emergencyNumbers.split(",")) { + // It is not possible to append additional digits to an emergency number to dial + // the number in Brazil - it won't connect. + if (useExactMatch || "BR".equalsIgnoreCase(defaultCountryIso)) { + if (number.equals(emergencyNum)) { + return true; + } + } else { + if (number.startsWith(emergencyNum)) { + return true; + } + } + } + // no matches found against the list! + return false; + } + + Rlog.d(LOG_TAG, "System property doesn't provide any emergency numbers." + + " Use embedded logic for determining ones."); + + // If slot id is invalid, means that there is no sim card. + // According spec 3GPP TS22.101, the following numbers should be + // ECC numbers when SIM/USIM is not present. + emergencyNumbers = ((slotId < 0) ? "112,911,000,08,110,118,119,999" : "112,911"); + + for (String emergencyNum : emergencyNumbers.split(",")) { + if (useExactMatch) { + if (number.equals(emergencyNum)) { + return true; + } + } else { + if (number.startsWith(emergencyNum)) { + return true; + } + } + } + + // No ecclist system property, so use our own list. + if (defaultCountryIso != null) { + ShortNumberInfo info = ShortNumberInfo.getInstance(); + if (useExactMatch) { + return info.isEmergencyNumber(number, defaultCountryIso); + } else { + return info.connectsToEmergencyNumber(number, defaultCountryIso); + } + } + + return false; + } + + /** * isVoiceMailNumber: checks a given number against the voicemail * number provided by the RIL and SIM card. The caller must have * the READ_PHONE_STATE credential. diff --git a/telephony/java/android/telephony/PhoneStateListener.java b/telephony/java/android/telephony/PhoneStateListener.java index e8a28cac3140..0df0dafbe1dd 100644 --- a/telephony/java/android/telephony/PhoneStateListener.java +++ b/telephony/java/android/telephony/PhoneStateListener.java @@ -27,12 +27,14 @@ import android.os.Bundle; import android.os.Handler; import android.os.HandlerExecutor; import android.os.Looper; +import android.telephony.emergency.EmergencyNumber; import com.android.internal.annotations.VisibleForTesting; import com.android.internal.telephony.IPhoneStateListener; import java.lang.ref.WeakReference; import java.util.List; +import java.util.Map; import java.util.concurrent.Executor; /** @@ -313,6 +315,8 @@ public class PhoneStateListener { * * <p>Requires permission {@link android.Manifest.permission#READ_PHONE_STATE} or the calling * app has carrier privileges (see {@link TelephonyManager#hasCarrierPrivileges}). + * + * @see #onEmergencyNumberListChanged */ public static final int LISTEN_EMERGENCY_NUMBER_LIST = 0x01000000; @@ -603,6 +607,21 @@ public class PhoneStateListener { } /** + * Callback invoked when the current emergency number list has changed + * + * @param emergencyNumberList Map including the key as the active subscription ID + * (Note: if there is no active subscription, the key is + * {@link SubscriptionManager#getDefaultSubscriptionId}) + * and the value as the list of {@link EmergencyNumber}; + * null if this information is not available. + * @hide + */ + public void onEmergencyNumberListChanged( + @NonNull Map<Integer, List<EmergencyNumber>> emergencyNumberList) { + // default implementation empty + } + + /** * Callback invoked when OEM hook raw event is received. Requires * the READ_PRIVILEGED_PHONE_STATE permission. * @param rawData is the byte array of the OEM hook raw data. @@ -859,6 +878,16 @@ public class PhoneStateListener { () -> psl.onPhysicalChannelConfigurationChanged(configs))); } + @Override + public void onEmergencyNumberListChanged(Map emergencyNumberList) { + PhoneStateListener psl = mPhoneStateListenerWeakRef.get(); + if (psl == null) return; + + Binder.withCleanCallingIdentity( + () -> mExecutor.execute( + () -> psl.onEmergencyNumberListChanged(emergencyNumberList))); + } + public void onPhoneCapabilityChanged(PhoneCapability capability) { PhoneStateListener psl = mPhoneStateListenerWeakRef.get(); if (psl == null) return; diff --git a/telephony/java/android/telephony/ServiceState.java b/telephony/java/android/telephony/ServiceState.java index 7c52d38b37b0..78f05168198f 100644 --- a/telephony/java/android/telephony/ServiceState.java +++ b/telephony/java/android/telephony/ServiceState.java @@ -1423,47 +1423,49 @@ public class ServiceState implements Parcelable { } /** @hide */ - public static int rilRadioTechnologyToNetworkType(@RilRadioTechnology int rt) { - switch(rt) { - case ServiceState.RIL_RADIO_TECHNOLOGY_GPRS: - return TelephonyManager.NETWORK_TYPE_GPRS; - case ServiceState.RIL_RADIO_TECHNOLOGY_EDGE: - return TelephonyManager.NETWORK_TYPE_EDGE; - case ServiceState.RIL_RADIO_TECHNOLOGY_UMTS: - return TelephonyManager.NETWORK_TYPE_UMTS; - case ServiceState.RIL_RADIO_TECHNOLOGY_HSDPA: - return TelephonyManager.NETWORK_TYPE_HSDPA; - case ServiceState.RIL_RADIO_TECHNOLOGY_HSUPA: - return TelephonyManager.NETWORK_TYPE_HSUPA; - case ServiceState.RIL_RADIO_TECHNOLOGY_HSPA: - return TelephonyManager.NETWORK_TYPE_HSPA; - case ServiceState.RIL_RADIO_TECHNOLOGY_IS95A: - case ServiceState.RIL_RADIO_TECHNOLOGY_IS95B: - return TelephonyManager.NETWORK_TYPE_CDMA; - case ServiceState.RIL_RADIO_TECHNOLOGY_1xRTT: - return TelephonyManager.NETWORK_TYPE_1xRTT; - case ServiceState.RIL_RADIO_TECHNOLOGY_EVDO_0: - return TelephonyManager.NETWORK_TYPE_EVDO_0; - case ServiceState.RIL_RADIO_TECHNOLOGY_EVDO_A: - return TelephonyManager.NETWORK_TYPE_EVDO_A; - case ServiceState.RIL_RADIO_TECHNOLOGY_EVDO_B: - return TelephonyManager.NETWORK_TYPE_EVDO_B; - case ServiceState.RIL_RADIO_TECHNOLOGY_EHRPD: - return TelephonyManager.NETWORK_TYPE_EHRPD; - case ServiceState.RIL_RADIO_TECHNOLOGY_LTE: - return TelephonyManager.NETWORK_TYPE_LTE; - case ServiceState.RIL_RADIO_TECHNOLOGY_HSPAP: - return TelephonyManager.NETWORK_TYPE_HSPAP; - case ServiceState.RIL_RADIO_TECHNOLOGY_GSM: - return TelephonyManager.NETWORK_TYPE_GSM; - case ServiceState.RIL_RADIO_TECHNOLOGY_TD_SCDMA: - return TelephonyManager.NETWORK_TYPE_TD_SCDMA; - case ServiceState.RIL_RADIO_TECHNOLOGY_IWLAN: - return TelephonyManager.NETWORK_TYPE_IWLAN; - case ServiceState.RIL_RADIO_TECHNOLOGY_LTE_CA: - return TelephonyManager.NETWORK_TYPE_LTE_CA; - default: - return TelephonyManager.NETWORK_TYPE_UNKNOWN; + public static int rilRadioTechnologyToNetworkType(@RilRadioTechnology int rat) { + switch(rat) { + case ServiceState.RIL_RADIO_TECHNOLOGY_GPRS: + return TelephonyManager.NETWORK_TYPE_GPRS; + case ServiceState.RIL_RADIO_TECHNOLOGY_EDGE: + return TelephonyManager.NETWORK_TYPE_EDGE; + case ServiceState.RIL_RADIO_TECHNOLOGY_UMTS: + return TelephonyManager.NETWORK_TYPE_UMTS; + case ServiceState.RIL_RADIO_TECHNOLOGY_HSDPA: + return TelephonyManager.NETWORK_TYPE_HSDPA; + case ServiceState.RIL_RADIO_TECHNOLOGY_HSUPA: + return TelephonyManager.NETWORK_TYPE_HSUPA; + case ServiceState.RIL_RADIO_TECHNOLOGY_HSPA: + return TelephonyManager.NETWORK_TYPE_HSPA; + case ServiceState.RIL_RADIO_TECHNOLOGY_IS95A: + case ServiceState.RIL_RADIO_TECHNOLOGY_IS95B: + return TelephonyManager.NETWORK_TYPE_CDMA; + case ServiceState.RIL_RADIO_TECHNOLOGY_1xRTT: + return TelephonyManager.NETWORK_TYPE_1xRTT; + case ServiceState.RIL_RADIO_TECHNOLOGY_EVDO_0: + return TelephonyManager.NETWORK_TYPE_EVDO_0; + case ServiceState.RIL_RADIO_TECHNOLOGY_EVDO_A: + return TelephonyManager.NETWORK_TYPE_EVDO_A; + case ServiceState.RIL_RADIO_TECHNOLOGY_EVDO_B: + return TelephonyManager.NETWORK_TYPE_EVDO_B; + case ServiceState.RIL_RADIO_TECHNOLOGY_EHRPD: + return TelephonyManager.NETWORK_TYPE_EHRPD; + case ServiceState.RIL_RADIO_TECHNOLOGY_LTE: + return TelephonyManager.NETWORK_TYPE_LTE; + case ServiceState.RIL_RADIO_TECHNOLOGY_HSPAP: + return TelephonyManager.NETWORK_TYPE_HSPAP; + case ServiceState.RIL_RADIO_TECHNOLOGY_GSM: + return TelephonyManager.NETWORK_TYPE_GSM; + case ServiceState.RIL_RADIO_TECHNOLOGY_TD_SCDMA: + return TelephonyManager.NETWORK_TYPE_TD_SCDMA; + case ServiceState.RIL_RADIO_TECHNOLOGY_IWLAN: + return TelephonyManager.NETWORK_TYPE_IWLAN; + case ServiceState.RIL_RADIO_TECHNOLOGY_LTE_CA: + return TelephonyManager.NETWORK_TYPE_LTE_CA; + case ServiceState.RIL_RADIO_TECHNOLOGY_NR: + return TelephonyManager.NETWORK_TYPE_NR; + default: + return TelephonyManager.NETWORK_TYPE_UNKNOWN; } } diff --git a/telephony/java/android/telephony/TelephonyManager.java b/telephony/java/android/telephony/TelephonyManager.java index fa9b76de2e6b..422e66de7e0b 100644 --- a/telephony/java/android/telephony/TelephonyManager.java +++ b/telephony/java/android/telephony/TelephonyManager.java @@ -810,6 +810,7 @@ public class TelephonyManager { * @see TelephonyManager#NETWORK_TYPE_LTE * @see TelephonyManager#NETWORK_TYPE_EHRPD * @see TelephonyManager#NETWORK_TYPE_HSPAP + * @see TelephonyManager#NETWORK_TYPE_NR * * <p class="note"> * Retrieve with @@ -2328,6 +2329,7 @@ public class TelephonyManager { * @see #NETWORK_TYPE_LTE * @see #NETWORK_TYPE_EHRPD * @see #NETWORK_TYPE_HSPAP + * @see #NETWORK_TYPE_NR * * @hide */ @@ -2379,6 +2381,7 @@ public class TelephonyManager { * @see #NETWORK_TYPE_LTE * @see #NETWORK_TYPE_EHRPD * @see #NETWORK_TYPE_HSPAP + * @see #NETWORK_TYPE_NR */ @SuppressAutoDoc // Blocked by b/72967236 - no support for carrier privileges @RequiresPermission(android.Manifest.permission.READ_PHONE_STATE) @@ -2565,6 +2568,8 @@ public class TelephonyManager { return "IWLAN"; case NETWORK_TYPE_LTE_CA: return "LTE_CA"; + case NETWORK_TYPE_NR: + return "NR"; default: return "UNKNOWN"; } @@ -9449,8 +9454,13 @@ public class TelephonyManager { /** * Get the emergency number list based on current locale, sim, default, modem and network. * - * <p>The emergency number {@link EmergencyNumber} with higher display priority is located at - * the smaller index in the returned list. + * <p>In each returned list, the emergency number {@link EmergencyNumber} coming from higher + * priority sources will be located at the smaller index; the priority order of sources are: + * {@link EmergencyNumber#EMERGENCY_NUMBER_SOURCE_NETWORK_SIGNALING} > + * {@link EmergencyNumber#EMERGENCY_NUMBER_SOURCE_SIM} > + * {@link EmergencyNumber#EMERGENCY_NUMBER_SOURCE_DATABASE} > + * {@link EmergencyNumber#EMERGENCY_NUMBER_SOURCE_DEFAULT} > + * {@link EmergencyNumber#EMERGENCY_NUMBER_SOURCE_MODEM_CONFIG} * * <p>The subscriptions which the returned list would be based on, are all the active * subscriptions, no matter which subscription could be used to create TelephonyManager. @@ -9459,8 +9469,9 @@ public class TelephonyManager { * app has carrier privileges (see {@link #hasCarrierPrivileges}). * * @return Map including the key as the active subscription ID (Note: if there is no active - * subscription, the key is {@link SubscriptionManager#DEFAULT_SUBSCRIPTION_ID}) and the value - * as the list of {@link EmergencyNumber}; null if this information is not available. + * subscription, the key is {@link SubscriptionManager#getDefaultSubscriptionId}) and the value + * as the list of {@link EmergencyNumber}; null if this information is not available; or throw + * a SecurityException if the caller does not have the permission. */ @RequiresPermission(android.Manifest.permission.READ_PHONE_STATE) @Nullable @@ -9481,8 +9492,13 @@ public class TelephonyManager { * Get the per-category emergency number list based on current locale, sim, default, modem * and network. * - * <p>The emergency number {@link EmergencyNumber} with higher display priority is located at - * the smaller index in the returned list. + * <p>In each returned list, the emergency number {@link EmergencyNumber} coming from higher + * priority sources will be located at the smaller index; the priority order of sources are: + * {@link EmergencyNumber#EMERGENCY_NUMBER_SOURCE_NETWORK_SIGNALING} > + * {@link EmergencyNumber#EMERGENCY_NUMBER_SOURCE_SIM} > + * {@link EmergencyNumber#EMERGENCY_NUMBER_SOURCE_DATABASE} > + * {@link EmergencyNumber#EMERGENCY_NUMBER_SOURCE_DEFAULT} > + * {@link EmergencyNumber#EMERGENCY_NUMBER_SOURCE_MODEM_CONFIG} * * <p>The subscriptions which the returned list would be based on, are all the active * subscriptions, no matter which subscription could be used to create TelephonyManager. @@ -9503,8 +9519,9 @@ public class TelephonyManager { * <li>{@link EmergencyNumber#EMERGENCY_SERVICE_CATEGORY_AIEC} </li> * </ol> * @return Map including the key as the active subscription ID (Note: if there is no active - * subscription, the key is {@link SubscriptionManager#DEFAULT_SUBSCRIPTION_ID}) and the value - * as the list of {@link EmergencyNumber}; null if this information is not available. + * subscription, the key is {@link SubscriptionManager#getDefaultSubscriptionId}) and the value + * as the list of {@link EmergencyNumber}; null if this information is not available; or throw + * a SecurityException if the caller does not have the permission. */ @RequiresPermission(android.Manifest.permission.READ_PHONE_STATE) @Nullable @@ -9551,7 +9568,44 @@ public class TelephonyManager { if (telephony == null) { return false; } - return telephony.isCurrentEmergencyNumber(number); + return telephony.isCurrentEmergencyNumber(number, true); + } catch (RemoteException ex) { + Log.e(TAG, "isCurrentEmergencyNumber RemoteException", ex); + } + return false; + } + + /** + * Checks if the supplied number is an emergency number based on current locale, sim, default, + * modem and network. + * + * <p> Specifically, this method will return {@code true} if the specified number is an + * emergency number, *or* if the number simply starts with the same digits as any current + * emergency number. + * + * <p>The subscriptions which the identification would be based on, are all the active + * subscriptions, no matter which subscription could be used to create TelephonyManager. + * + * <p>Requires permission: {@link android.Manifest.permission#READ_PRIVILEGED_PHONE_STATE} or + * that the calling app has carrier privileges (see {@link #hasCarrierPrivileges}). + * + * @param number - the number to look up + * @return {@code true} if the given number is an emergency number or it simply starts with + * the same digits of any current emergency number based on current locale, sim, modem and + * network; {@code false} if it is not; or throw an SecurityException if the caller does not + * have the required permission/privileges + * + * @hide + */ + @SystemApi + @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) + public boolean isCurrentPotentialEmergencyNumber(@NonNull String number) { + try { + ITelephony telephony = getITelephony(); + if (telephony == null) { + return false; + } + return telephony.isCurrentEmergencyNumber(number, false); } catch (RemoteException ex) { Log.e(TAG, "isCurrentEmergencyNumber RemoteException", ex); } diff --git a/telephony/java/android/telephony/emergency/EmergencyNumber.java b/telephony/java/android/telephony/emergency/EmergencyNumber.java index 41f7bd7ade63..fe062d5d974a 100644 --- a/telephony/java/android/telephony/emergency/EmergencyNumber.java +++ b/telephony/java/android/telephony/emergency/EmergencyNumber.java @@ -22,6 +22,7 @@ import android.hardware.radio.V1_4.EmergencyNumberSource; import android.hardware.radio.V1_4.EmergencyServiceCategory; import android.os.Parcel; import android.os.Parcelable; +import android.telephony.Rlog; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; @@ -150,6 +151,7 @@ public final class EmergencyNumber implements Parcelable, Comparable<EmergencyNu @IntDef(flag = true, prefix = { "EMERGENCY_NUMBER_SOURCE_" }, value = { EMERGENCY_NUMBER_SOURCE_NETWORK_SIGNALING, EMERGENCY_NUMBER_SOURCE_SIM, + EMERGENCY_NUMBER_SOURCE_DATABASE, EMERGENCY_NUMBER_SOURCE_MODEM_CONFIG, EMERGENCY_NUMBER_SOURCE_DEFAULT }) @@ -169,6 +171,10 @@ public final class EmergencyNumber implements Parcelable, Comparable<EmergencyNu * Reference: 3gpp 22.101, Section 10 - Emergency Calls */ public static final int EMERGENCY_NUMBER_SOURCE_SIM = EmergencyNumberSource.SIM; + /** + * Bit-field which indicates the number is from the platform-maintained database. + */ + public static final int EMERGENCY_NUMBER_SOURCE_DATABASE = 1 << 4; /** Bit-field which indicates the number is from the modem config. */ public static final int EMERGENCY_NUMBER_SOURCE_MODEM_CONFIG = EmergencyNumberSource.MODEM_CONFIG; @@ -187,21 +193,24 @@ public final class EmergencyNumber implements Parcelable, Comparable<EmergencyNu EMERGENCY_NUMBER_SOURCE_SET = new HashSet<Integer>(); EMERGENCY_NUMBER_SOURCE_SET.add(EMERGENCY_NUMBER_SOURCE_NETWORK_SIGNALING); EMERGENCY_NUMBER_SOURCE_SET.add(EMERGENCY_NUMBER_SOURCE_SIM); + EMERGENCY_NUMBER_SOURCE_SET.add(EMERGENCY_NUMBER_SOURCE_DATABASE); EMERGENCY_NUMBER_SOURCE_SET.add(EMERGENCY_NUMBER_SOURCE_MODEM_CONFIG); EMERGENCY_NUMBER_SOURCE_SET.add(EMERGENCY_NUMBER_SOURCE_DEFAULT); } private final String mNumber; private final String mCountryIso; + private final String mMnc; private final int mEmergencyServiceCategoryBitmask; private final int mEmergencyNumberSourceBitmask; /** @hide */ public EmergencyNumber(@NonNull String number, @NonNull String countryIso, - int emergencyServiceCategories, + @NonNull String mnc, int emergencyServiceCategories, int emergencyNumberSources) { this.mNumber = number; this.mCountryIso = countryIso; + this.mMnc = mnc; this.mEmergencyServiceCategoryBitmask = emergencyServiceCategories; this.mEmergencyNumberSourceBitmask = emergencyNumberSources; } @@ -210,6 +219,7 @@ public final class EmergencyNumber implements Parcelable, Comparable<EmergencyNu public EmergencyNumber(Parcel source) { mNumber = source.readString(); mCountryIso = source.readString(); + mMnc = source.readString(); mEmergencyServiceCategoryBitmask = source.readInt(); mEmergencyNumberSourceBitmask = source.readInt(); } @@ -236,6 +246,15 @@ public final class EmergencyNumber implements Parcelable, Comparable<EmergencyNu } /** + * Get the Mobile Network Code of the emergency number. + * + * @return the Mobile Network Code of the emergency number. + */ + public String getMnc() { + return mMnc; + } + + /** * Returns the bitmask of emergency service categories of the emergency number. * * @return bitmask of the emergency service categories @@ -338,6 +357,7 @@ public final class EmergencyNumber implements Parcelable, Comparable<EmergencyNu public void writeToParcel(Parcel dest, int flags) { dest.writeString(mNumber); dest.writeString(mCountryIso); + dest.writeString(mMnc); dest.writeInt(mEmergencyServiceCategoryBitmask); dest.writeInt(mEmergencyNumberSourceBitmask); } @@ -350,10 +370,10 @@ public final class EmergencyNumber implements Parcelable, Comparable<EmergencyNu @Override public String toString() { - return "EmergencyNumber = " + "[Number]" + mNumber + " / [CountryIso]" + mCountryIso - + " / [ServiceCategories]" - + Integer.toBinaryString(mEmergencyServiceCategoryBitmask) - + " / [Sources]" + Integer.toBinaryString(mEmergencyNumberSourceBitmask); + return "EmergencyNumber:" + "Number-" + mNumber + "|CountryIso-" + mCountryIso + + "|Mnc-" + mMnc + + "|ServiceCategories-" + Integer.toBinaryString(mEmergencyServiceCategoryBitmask) + + "|Sources-" + Integer.toBinaryString(mEmergencyNumberSourceBitmask); } @Override @@ -373,6 +393,7 @@ public final class EmergencyNumber implements Parcelable, Comparable<EmergencyNu * The priority of sources are defined as follows: * EMERGENCY_NUMBER_SOURCE_NETWORK_SIGNALING > * EMERGENCY_NUMBER_SOURCE_SIM > + * EMERGENCY_NUMBER_SOURCE_DATABASE > * EMERGENCY_NUMBER_SOURCE_DEFAULT > * EMERGENCY_NUMBER_SOURCE_MODEM_CONFIG * @@ -385,7 +406,9 @@ public final class EmergencyNumber implements Parcelable, Comparable<EmergencyNu if (this.isFromSources(EMERGENCY_NUMBER_SOURCE_SIM)) { score += 1 << 3; } - // TODO add a score if the number comes from Google's emergency number database + if (this.isFromSources(EMERGENCY_NUMBER_SOURCE_DATABASE)) { + score += 1 << 2; + } if (this.isFromSources(EMERGENCY_NUMBER_SOURCE_DEFAULT)) { score += 1 << 1; } @@ -412,14 +435,104 @@ public final class EmergencyNumber implements Parcelable, Comparable<EmergencyNu < emergencyNumber.getDisplayPriorityScore()) { return 1; } else { - /** - * TODO if both numbers have the same display priority score, the number matches the - * Google's emergency number database has a higher display priority. - */ return 0; } } + /** + * In-place merge same emergency numbers in the emergency number list. + * + * A unique EmergencyNumber has a unique combination of ‘number’, ‘mcc’, 'mnc' and + * 'categories' fields. Multiple Emergency Number Sources should be merged into one bitfield + * for the same EmergencyNumber. + * + * @param emergencyNumberList the emergency number list to process + * + * @hide + */ + public static void mergeSameNumbersInEmergencyNumberList( + List<EmergencyNumber> emergencyNumberList) { + if (emergencyNumberList == null) { + return; + } + Set<EmergencyNumber> mergedEmergencyNumber = new HashSet<>(); + for (int i = 0; i < emergencyNumberList.size(); i++) { + // Skip the check because it was merged. + if (mergedEmergencyNumber.contains(emergencyNumberList.get(i))) { + continue; + } + for (int j = i + 1; j < emergencyNumberList.size(); j++) { + if (isSameEmergencyNumber( + emergencyNumberList.get(i), emergencyNumberList.get(j))) { + Rlog.e(LOG_TAG, "Found unexpected duplicate numbers: " + + emergencyNumberList.get(i) + " vs " + emergencyNumberList.get(j)); + // Set the merged emergency number in the current position + emergencyNumberList.set(i, mergeNumbers( + emergencyNumberList.get(i), emergencyNumberList.get(j))); + // Mark the emergency number has been merged + mergedEmergencyNumber.add(emergencyNumberList.get(j)); + } + } + } + // Remove the marked emergency number in the orignal list + for (int i = 0; i < emergencyNumberList.size(); i++) { + if (mergedEmergencyNumber.contains(emergencyNumberList.get(i))) { + emergencyNumberList.remove(i--); + } + } + } + + /** + * Check if two emergency numbers are the same. + * + * A unique EmergencyNumber has a unique combination of ‘number’, ‘mcc’, 'mnc' and + * 'categories' fields. Multiple Emergency Number Sources should be merged into one bitfield + * for the same EmergencyNumber. + * + * @param first first EmergencyNumber to compare + * @param second second EmergencyNumber to compare + * @return true if they are the same EmergencyNumbers; false otherwise. + * + * @hide + */ + public static boolean isSameEmergencyNumber(@NonNull EmergencyNumber first, + @NonNull EmergencyNumber second) { + if (!first.getNumber().equals(second.getNumber())) { + return false; + } + if (!first.getCountryIso().equals(second.getCountryIso())) { + return false; + } + if (!first.getMnc().equals(second.getMnc())) { + return false; + } + if (first.getEmergencyServiceCategoryBitmask() + != second.getEmergencyServiceCategoryBitmask()) { + return false; + } + return true; + } + + /** + * Get a merged EmergencyNumber for two numbers if they are the same. + * + * @param first first EmergencyNumber to compare + * @param second second EmergencyNumber to compare + * @return a merged EmergencyNumber or null if they are not the same EmergencyNumber + * + * @hide + */ + public static EmergencyNumber mergeNumbers(@NonNull EmergencyNumber first, + @NonNull EmergencyNumber second) { + if (isSameEmergencyNumber(first, second)) { + return new EmergencyNumber(first.getNumber(), first.getCountryIso(), first.getMnc(), + first.getEmergencyServiceCategoryBitmask(), + first.getEmergencyNumberSourceBitmask() + | second.getEmergencyNumberSourceBitmask()); + } + return null; + } + public static final Parcelable.Creator<EmergencyNumber> CREATOR = new Parcelable.Creator<EmergencyNumber>() { @Override diff --git a/telephony/java/com/android/internal/telephony/IPhoneStateListener.aidl b/telephony/java/com/android/internal/telephony/IPhoneStateListener.aidl index 79f0635c67f7..78fc0bc487bf 100644 --- a/telephony/java/com/android/internal/telephony/IPhoneStateListener.aidl +++ b/telephony/java/com/android/internal/telephony/IPhoneStateListener.aidl @@ -25,6 +25,7 @@ import android.telephony.PhoneCapability; import android.telephony.PhysicalChannelConfig; import android.telephony.PreciseCallState; import android.telephony.PreciseDataConnectionState; +import android.telephony.emergency.EmergencyNumber; oneway interface IPhoneStateListener { void onServiceStateChanged(in ServiceState serviceState); @@ -53,5 +54,6 @@ oneway interface IPhoneStateListener { void onPhoneCapabilityChanged(in PhoneCapability capability); void onPreferredDataSubIdChanged(in int subId); void onRadioPowerStateChanged(in int state); + void onEmergencyNumberListChanged(in Map emergencyNumberList); } diff --git a/telephony/java/com/android/internal/telephony/ITelephony.aidl b/telephony/java/com/android/internal/telephony/ITelephony.aidl index 399dc5255176..88b9302afacb 100644 --- a/telephony/java/com/android/internal/telephony/ITelephony.aidl +++ b/telephony/java/com/android/internal/telephony/ITelephony.aidl @@ -1716,7 +1716,7 @@ interface ITelephony { /** * Identify if the number is emergency number, based on all the active subscriptions. */ - boolean isCurrentEmergencyNumber(String number); + boolean isCurrentEmergencyNumber(String number, boolean exactMatch); /** * Return a list of certs in hex string from loaded carrier privileges access rules. diff --git a/telephony/java/com/android/internal/telephony/ITelephonyRegistry.aidl b/telephony/java/com/android/internal/telephony/ITelephonyRegistry.aidl index 76e7509c1094..d9f5c3f6d0fa 100644 --- a/telephony/java/com/android/internal/telephony/ITelephonyRegistry.aidl +++ b/telephony/java/com/android/internal/telephony/ITelephonyRegistry.aidl @@ -81,5 +81,5 @@ interface ITelephonyRegistry { void notifyPhoneCapabilityChanged(in PhoneCapability capability); void notifyPreferredDataSubIdChanged(int preferredSubId); void notifyRadioPowerStateChanged(in int state); - void notifyEmergencyNumberList(in List<EmergencyNumber> emergencyNumberList); + void notifyEmergencyNumberList(); } diff --git a/telephony/java/com/android/internal/telephony/RILConstants.java b/telephony/java/com/android/internal/telephony/RILConstants.java index cb8269efe443..c9343171e03e 100644 --- a/telephony/java/com/android/internal/telephony/RILConstants.java +++ b/telephony/java/com/android/internal/telephony/RILConstants.java @@ -483,4 +483,5 @@ public interface RILConstants { int RIL_UNSOL_HAL_NON_RIL_BASE = 1100; int RIL_UNSOL_ICC_SLOT_STATUS = 1100; int RIL_UNSOL_PHYSICAL_CHANNEL_CONFIG = 1101; + int RIL_UNSOL_EMERGENCY_NUMBER_LIST = 1102; } |