Merge "Atom: Update BluetoothConnectionStateChanged atom"
diff --git a/Android.bp b/Android.bp
index ab2bd9d..580df85 100644
--- a/Android.bp
+++ b/Android.bp
@@ -704,7 +704,6 @@
required: [
// TODO: remove gps_debug when the build system propagates "required" properly.
"gps_debug.conf",
- "libtextclassifier",
// Loaded with System.loadLibrary by android.view.textclassifier
"libmedia2_jni",
],
@@ -830,7 +829,12 @@
"core/java/android/net/IIpMemoryStore.aidl",
"core/java/android/net/INetworkStackConnector.aidl",
"core/java/android/net/INetworkStackStatusCallback.aidl",
+ "core/java/android/net/IpPrefixParcelable.aidl",
+ "core/java/android/net/LinkAddressParcelable.aidl",
+ "core/java/android/net/LinkPropertiesParcelable.aidl",
"core/java/android/net/PrivateDnsConfigParcel.aidl",
+ "core/java/android/net/ProxyInfoParcelable.aidl",
+ "core/java/android/net/RouteInfoParcelable.aidl",
"core/java/android/net/dhcp/DhcpServingParamsParcel.aidl",
"core/java/android/net/dhcp/IDhcpServer.aidl",
"core/java/android/net/dhcp/IDhcpServerCallbacks.aidl",
@@ -850,6 +854,10 @@
"nist-sip",
"tagsoup",
"rappor",
+ "libtextclassifier-java",
+ ],
+ required: [
+ "libtextclassifier",
],
dxflags: ["--core-library"],
}
@@ -1256,7 +1264,6 @@
"ext",
"framework",
"voip-common",
- "android.test.mock.impl",
],
local_sourcepaths: frameworks_base_subdirs,
installable: false,
diff --git a/api/current.txt b/api/current.txt
index 7c7429f..e4ecd5e 100755
--- a/api/current.txt
+++ b/api/current.txt
@@ -41302,10 +41302,10 @@
ctor public CallRedirectionService();
method public final void cancelCall();
method public final android.os.IBinder onBind(android.content.Intent);
- method public abstract void onPlaceCall(android.net.Uri, android.telecom.PhoneAccountHandle);
+ method public abstract void onPlaceCall(android.net.Uri, android.telecom.PhoneAccountHandle, boolean);
method public final boolean onUnbind(android.content.Intent);
method public final void placeCallUnmodified();
- method public final void redirectCall(android.net.Uri, android.telecom.PhoneAccountHandle);
+ method public final void redirectCall(android.net.Uri, android.telecom.PhoneAccountHandle, boolean);
field public static final java.lang.String SERVICE_INTERFACE = "android.telecom.CallRedirectionService";
}
@@ -43336,7 +43336,7 @@
field public static final int PROTOCOL_IPV6 = 1; // 0x1
field public static final int PROTOCOL_PPP = 3; // 0x3
field public static final int TYPE_CBS = 128; // 0x80
- field public static final int TYPE_DEFAULT = 1; // 0x1
+ field public static final int TYPE_DEFAULT = 17; // 0x11
field public static final int TYPE_DUN = 8; // 0x8
field public static final int TYPE_EMERGENCY = 512; // 0x200
field public static final int TYPE_FOTA = 32; // 0x20
@@ -43380,6 +43380,7 @@
method public int compareTo(android.telephony.emergency.EmergencyNumber);
method public int describeContents();
method public java.lang.String getCountryIso();
+ method public int getEmergencyCallRouting();
method public int getEmergencyNumberSourceBitmask();
method public java.util.List<java.lang.Integer> getEmergencyNumberSources();
method public java.util.List<java.lang.Integer> getEmergencyServiceCategories();
@@ -43390,6 +43391,9 @@
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_CALL_ROUTING_EMERGENCY = 1; // 0x1
+ field public static final int EMERGENCY_CALL_ROUTING_NORMAL = 2; // 0x2
+ field public static final int EMERGENCY_CALL_ROUTING_UNKNOWN = 0; // 0x0
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
@@ -43427,6 +43431,7 @@
}
public class EuiccManager {
+ method public android.telephony.euicc.EuiccManager createForCardId(int);
method public void deleteSubscription(int, android.app.PendingIntent);
method public void downloadSubscription(android.telephony.euicc.DownloadableSubscription, boolean, android.app.PendingIntent);
method public java.lang.String getEid();
diff --git a/api/system-current.txt b/api/system-current.txt
index 1bf6cf9..9cdc682 100644
--- a/api/system-current.txt
+++ b/api/system-current.txt
@@ -6040,6 +6040,7 @@
method public android.os.Bundle getCallExtras();
method public int getCallType();
method public static int getCallTypeFromVideoState(int);
+ method public int getEmergencyCallRouting();
method public int getEmergencyServiceCategories();
method public android.telephony.ims.ImsStreamMediaProfile getMediaProfile();
method public int getRestrictCause();
@@ -6053,6 +6054,7 @@
method public void setCallExtraBoolean(java.lang.String, boolean);
method public void setCallExtraInt(java.lang.String, int);
method public void setCallRestrictCause(int);
+ method public void setEmergencyCallRouting(int);
method public void setEmergencyServiceCategories(int);
method public void updateCallExtras(android.telephony.ims.ImsCallProfile);
method public void updateCallType(android.telephony.ims.ImsCallProfile);
diff --git a/config/hiddenapi-greylist.txt b/config/hiddenapi-greylist.txt
index 7b1c26a..2bd813e 100644
--- a/config/hiddenapi-greylist.txt
+++ b/config/hiddenapi-greylist.txt
@@ -3643,11 +3643,9 @@
Lcom/android/internal/telephony/SubscriptionInfoUpdater;->mContext:Landroid/content/Context;
Lcom/android/internal/telephony/SubscriptionInfoUpdater;->mCurrentlyActiveUserId:I
Lcom/android/internal/telephony/SubscriptionInfoUpdater;->mIccId:[Ljava/lang/String;
-Lcom/android/internal/telephony/SubscriptionInfoUpdater;->mInsertSimState:[I
Lcom/android/internal/telephony/SubscriptionInfoUpdater;->mPackageManager:Landroid/content/pm/IPackageManager;
Lcom/android/internal/telephony/SubscriptionInfoUpdater;->mPhone:[Lcom/android/internal/telephony/Phone;
Lcom/android/internal/telephony/SubscriptionInfoUpdater;->PROJECT_SIM_NUM:I
-Lcom/android/internal/telephony/SubscriptionInfoUpdater;->updateSubscriptionInfoByIccId()V
Lcom/android/internal/telephony/TelephonyCapabilities;->supportsAdn(I)Z
Lcom/android/internal/telephony/TelephonyProperties;->PROPERTY_ICC_OPERATOR_NUMERIC:Ljava/lang/String;
Lcom/android/internal/telephony/test/InterpreterEx;-><init>(Ljava/lang/String;)V
diff --git a/core/java/android/net/IpPrefixParcelable.aidl b/core/java/android/net/IpPrefixParcelable.aidl
new file mode 100644
index 0000000..93a8d41
--- /dev/null
+++ b/core/java/android/net/IpPrefixParcelable.aidl
@@ -0,0 +1,22 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+*/
+
+package android.net;
+
+parcelable IpPrefixParcelable {
+ String address;
+ int prefixLength;
+}
\ No newline at end of file
diff --git a/core/java/android/net/LinkAddressParcelable.aidl b/core/java/android/net/LinkAddressParcelable.aidl
new file mode 100644
index 0000000..af8e79b
--- /dev/null
+++ b/core/java/android/net/LinkAddressParcelable.aidl
@@ -0,0 +1,24 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+*/
+
+package android.net;
+
+parcelable LinkAddressParcelable {
+ String address;
+ int prefixLength;
+ int flags;
+ int scope;
+}
\ No newline at end of file
diff --git a/core/java/android/net/LinkPropertiesParcelable.aidl b/core/java/android/net/LinkPropertiesParcelable.aidl
new file mode 100644
index 0000000..b153dc7
--- /dev/null
+++ b/core/java/android/net/LinkPropertiesParcelable.aidl
@@ -0,0 +1,39 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+*/
+
+package android.net;
+
+import android.net.IpPrefixParcelable;
+import android.net.LinkAddressParcelable;
+import android.net.ProxyInfoParcelable;
+import android.net.RouteInfoParcelable;
+
+parcelable LinkPropertiesParcelable {
+ String ifaceName;
+ LinkAddressParcelable[] linkAddresses;
+ String[] dnses;
+ String[] pcscfs;
+ String[] validatedPrivateDnses;
+ boolean usePrivateDns;
+ String privateDnsServerName;
+ String domains;
+ RouteInfoParcelable[] routes;
+ ProxyInfoParcelable httpProxy;
+ int mtu;
+ String tcpBufferSizes;
+ IpPrefixParcelable nat64Prefix;
+ LinkPropertiesParcelable[] stackedLinks;
+}
\ No newline at end of file
diff --git a/core/java/android/net/ProxyInfoParcelable.aidl b/core/java/android/net/ProxyInfoParcelable.aidl
new file mode 100644
index 0000000..59fd846
--- /dev/null
+++ b/core/java/android/net/ProxyInfoParcelable.aidl
@@ -0,0 +1,24 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+*/
+
+package android.net;
+
+parcelable ProxyInfoParcelable {
+ String host;
+ int port;
+ String[] exclusionList;
+ String pacFileUrl;
+}
diff --git a/core/java/android/net/RouteInfoParcelable.aidl b/core/java/android/net/RouteInfoParcelable.aidl
new file mode 100644
index 0000000..15bcdcf
--- /dev/null
+++ b/core/java/android/net/RouteInfoParcelable.aidl
@@ -0,0 +1,26 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+*/
+
+package android.net;
+
+import android.net.IpPrefixParcelable;
+
+parcelable RouteInfoParcelable {
+ IpPrefixParcelable destination;
+ String gatewayAddr;
+ String ifaceName;
+ int type;
+}
diff --git a/core/java/android/view/LayoutInflater.java b/core/java/android/view/LayoutInflater.java
index 7232890..f2259b0 100644
--- a/core/java/android/view/LayoutInflater.java
+++ b/core/java/android/view/LayoutInflater.java
@@ -28,6 +28,7 @@
import android.graphics.Canvas;
import android.os.Handler;
import android.os.Message;
+import android.os.SystemProperties;
import android.os.Trace;
import android.util.AttributeSet;
import android.util.Log;
@@ -37,6 +38,9 @@
import com.android.internal.R;
+import dalvik.system.PathClassLoader;
+import java.io.File;
+import java.lang.reflect.Method;
import org.xmlpull.v1.XmlPullParser;
import org.xmlpull.v1.XmlPullParserException;
@@ -71,6 +75,10 @@
private static final String TAG = LayoutInflater.class.getSimpleName();
private static final boolean DEBUG = false;
+ private static final String USE_PRECOMPILED_LAYOUT_SYSTEM_PROPERTY
+ = "view.precompiled_layout_enabled";
+ private static final String COMPILED_VIEW_DEX_FILE_NAME = "/compiled_view.dex";
+
/** Empty stack trace used to avoid log spam in re-throw exceptions. */
private static final StackTraceElement[] EMPTY_STACK_TRACE = new StackTraceElement[0];
@@ -92,6 +100,13 @@
private Factory2 mPrivateFactory;
private Filter mFilter;
+ // Indicates whether we should try to inflate layouts using a precompiled layout instead of
+ // inflating from the XML resource.
+ private boolean mUseCompiledView;
+ // This variable holds the classloader that will be used to look for precompiled layouts. The
+ // The classloader includes the generated compiled_view.dex file.
+ private ClassLoader mPrecompiledClassLoader;
+
@UnsupportedAppUsage
final Object[] mConstructorArgs = new Object[2];
@@ -214,6 +229,7 @@
*/
protected LayoutInflater(Context context) {
mContext = context;
+ initPrecompiledViews();
}
/**
@@ -230,6 +246,7 @@
mFactory2 = original.mFactory2;
mPrivateFactory = original.mPrivateFactory;
setFilter(original.mFilter);
+ initPrecompiledViews();
}
/**
@@ -371,6 +388,29 @@
}
}
+ private void initPrecompiledViews() {
+ try {
+ mUseCompiledView =
+ SystemProperties.getBoolean(USE_PRECOMPILED_LAYOUT_SYSTEM_PROPERTY, false);
+ if (mUseCompiledView) {
+ mPrecompiledClassLoader = mContext.getClassLoader();
+ String dexFile = mContext.getCodeCacheDir() + COMPILED_VIEW_DEX_FILE_NAME;
+ if (new File(dexFile).exists()) {
+ mPrecompiledClassLoader = new PathClassLoader(dexFile, mPrecompiledClassLoader);
+ } else {
+ // If the precompiled layout file doesn't exist, then disable precompiled
+ // layouts.
+ mUseCompiledView = false;
+ }
+ }
+ } catch (Throwable e) {
+ if (DEBUG) {
+ Log.e(TAG, "Failed to initialized precompiled views layouts", e);
+ }
+ mUseCompiledView = false;
+ }
+ }
+
/**
* Inflate a new view hierarchy from the specified xml resource. Throws
* {@link InflateException} if there is an error.
@@ -427,10 +467,14 @@
final Resources res = getContext().getResources();
if (DEBUG) {
Log.d(TAG, "INFLATING from resource: \"" + res.getResourceName(resource) + "\" ("
- + Integer.toHexString(resource) + ")");
+ + Integer.toHexString(resource) + ")");
}
- final XmlResourceParser parser = res.getLayout(resource);
+ View view = tryInflatePrecompiled(resource, res, root, attachToRoot);
+ if (view != null) {
+ return view;
+ }
+ XmlResourceParser parser = res.getLayout(resource);
try {
return inflate(parser, root, attachToRoot);
} finally {
@@ -438,6 +482,73 @@
}
}
+ private @Nullable
+ View tryInflatePrecompiled(@LayoutRes int resource, Resources res, @Nullable ViewGroup root,
+ boolean attachToRoot) {
+ if (!mUseCompiledView) {
+ return null;
+ }
+
+ Trace.traceBegin(Trace.TRACE_TAG_VIEW, "inflate (precompiled)");
+
+ // Try to inflate using a precompiled layout.
+ String pkg = res.getResourcePackageName(resource);
+ String layout = res.getResourceEntryName(resource);
+
+ try {
+ Class clazz = mPrecompiledClassLoader.loadClass("" + pkg + ".CompiledView");
+ Method inflater = clazz.getMethod(layout, Context.class, int.class);
+ View view = (View) inflater.invoke(null, mContext, resource);
+
+ if (view != null && root != null) {
+ // We were able to use the precompiled inflater, but now we need to do some work to
+ // attach the view to the root correctly.
+ XmlResourceParser parser = res.getLayout(resource);
+ try {
+ AttributeSet attrs = Xml.asAttributeSet(parser);
+ advanceToRootNode(parser);
+ ViewGroup.LayoutParams params = root.generateLayoutParams(attrs);
+
+ if (attachToRoot) {
+ root.addView(view, params);
+ } else {
+ view.setLayoutParams(params);
+ }
+ } finally {
+ parser.close();
+ }
+ }
+
+ return view;
+ } catch (Throwable e) {
+ if (DEBUG) {
+ Log.e(TAG, "Failed to use precompiled view", e);
+ }
+ } finally {
+ Trace.traceEnd(Trace.TRACE_TAG_VIEW);
+ }
+ return null;
+ }
+
+ /**
+ * Advances the given parser to the first START_TAG. Throws InflateException if no start tag is
+ * found.
+ */
+ private void advanceToRootNode(XmlPullParser parser)
+ throws InflateException, IOException, XmlPullParserException {
+ // Look for the root node.
+ int type;
+ while ((type = parser.next()) != XmlPullParser.START_TAG &&
+ type != XmlPullParser.END_DOCUMENT) {
+ // Empty
+ }
+
+ if (type != XmlPullParser.START_TAG) {
+ throw new InflateException(parser.getPositionDescription()
+ + ": No start tag found!");
+ }
+ }
+
/**
* Inflate a new view hierarchy from the specified XML node. Throws
* {@link InflateException} if there is an error.
@@ -471,18 +582,7 @@
View result = root;
try {
- // Look for the root node.
- int type;
- while ((type = parser.next()) != XmlPullParser.START_TAG &&
- type != XmlPullParser.END_DOCUMENT) {
- // Empty
- }
-
- if (type != XmlPullParser.START_TAG) {
- throw new InflateException(parser.getPositionDescription()
- + ": No start tag found!");
- }
-
+ advanceToRootNode(parser);
final String name = parser.getName();
if (DEBUG) {
@@ -985,82 +1085,85 @@
+ "reference. The layout ID " + value + " is not valid.");
}
- final XmlResourceParser childParser = context.getResources().getLayout(layout);
+ final View precompiled = tryInflatePrecompiled(layout, context.getResources(),
+ (ViewGroup) parent, /*attachToRoot=*/true);
+ if (precompiled == null) {
+ final XmlResourceParser childParser = context.getResources().getLayout(layout);
- try {
- final AttributeSet childAttrs = Xml.asAttributeSet(childParser);
+ try {
+ final AttributeSet childAttrs = Xml.asAttributeSet(childParser);
- while ((type = childParser.next()) != XmlPullParser.START_TAG &&
- type != XmlPullParser.END_DOCUMENT) {
- // Empty.
+ while ((type = childParser.next()) != XmlPullParser.START_TAG &&
+ type != XmlPullParser.END_DOCUMENT) {
+ // Empty.
+ }
+
+ if (type != XmlPullParser.START_TAG) {
+ throw new InflateException(childParser.getPositionDescription() +
+ ": No start tag found!");
+ }
+
+ final String childName = childParser.getName();
+
+ if (TAG_MERGE.equals(childName)) {
+ // The <merge> tag doesn't support android:theme, so
+ // nothing special to do here.
+ rInflate(childParser, parent, context, childAttrs, false);
+ } else {
+ final View view = createViewFromTag(parent, childName,
+ context, childAttrs, hasThemeOverride);
+ final ViewGroup group = (ViewGroup) parent;
+
+ final TypedArray a = context.obtainStyledAttributes(
+ attrs, R.styleable.Include);
+ final int id = a.getResourceId(R.styleable.Include_id, View.NO_ID);
+ final int visibility = a.getInt(R.styleable.Include_visibility, -1);
+ a.recycle();
+
+ // We try to load the layout params set in the <include /> tag.
+ // If the parent can't generate layout params (ex. missing width
+ // or height for the framework ViewGroups, though this is not
+ // necessarily true of all ViewGroups) then we expect it to throw
+ // a runtime exception.
+ // We catch this exception and set localParams accordingly: true
+ // means we successfully loaded layout params from the <include>
+ // tag, false means we need to rely on the included layout params.
+ ViewGroup.LayoutParams params = null;
+ try {
+ params = group.generateLayoutParams(attrs);
+ } catch (RuntimeException e) {
+ // Ignore, just fail over to child attrs.
+ }
+ if (params == null) {
+ params = group.generateLayoutParams(childAttrs);
+ }
+ view.setLayoutParams(params);
+
+ // Inflate all children.
+ rInflateChildren(childParser, view, childAttrs, true);
+
+ if (id != View.NO_ID) {
+ view.setId(id);
+ }
+
+ switch (visibility) {
+ case 0:
+ view.setVisibility(View.VISIBLE);
+ break;
+ case 1:
+ view.setVisibility(View.INVISIBLE);
+ break;
+ case 2:
+ view.setVisibility(View.GONE);
+ break;
+ }
+
+ group.addView(view);
+ }
+ } finally {
+ childParser.close();
}
-
- if (type != XmlPullParser.START_TAG) {
- throw new InflateException(childParser.getPositionDescription() +
- ": No start tag found!");
- }
-
- final String childName = childParser.getName();
-
- if (TAG_MERGE.equals(childName)) {
- // The <merge> tag doesn't support android:theme, so
- // nothing special to do here.
- rInflate(childParser, parent, context, childAttrs, false);
- } else {
- final View view = createViewFromTag(parent, childName,
- context, childAttrs, hasThemeOverride);
- final ViewGroup group = (ViewGroup) parent;
-
- final TypedArray a = context.obtainStyledAttributes(
- attrs, R.styleable.Include);
- final int id = a.getResourceId(R.styleable.Include_id, View.NO_ID);
- final int visibility = a.getInt(R.styleable.Include_visibility, -1);
- a.recycle();
-
- // We try to load the layout params set in the <include /> tag.
- // If the parent can't generate layout params (ex. missing width
- // or height for the framework ViewGroups, though this is not
- // necessarily true of all ViewGroups) then we expect it to throw
- // a runtime exception.
- // We catch this exception and set localParams accordingly: true
- // means we successfully loaded layout params from the <include>
- // tag, false means we need to rely on the included layout params.
- ViewGroup.LayoutParams params = null;
- try {
- params = group.generateLayoutParams(attrs);
- } catch (RuntimeException e) {
- // Ignore, just fail over to child attrs.
- }
- if (params == null) {
- params = group.generateLayoutParams(childAttrs);
- }
- view.setLayoutParams(params);
-
- // Inflate all children.
- rInflateChildren(childParser, view, childAttrs, true);
-
- if (id != View.NO_ID) {
- view.setId(id);
- }
-
- switch (visibility) {
- case 0:
- view.setVisibility(View.VISIBLE);
- break;
- case 1:
- view.setVisibility(View.INVISIBLE);
- break;
- case 2:
- view.setVisibility(View.GONE);
- break;
- }
-
- group.addView(view);
- }
- } finally {
- childParser.close();
}
-
LayoutInflater.consumeChildElements(parser);
}
diff --git a/core/java/android/view/textclassifier/TextClassifierImpl.java b/core/java/android/view/textclassifier/TextClassifierImpl.java
index 6e5751a..00a267c 100644
--- a/core/java/android/view/textclassifier/TextClassifierImpl.java
+++ b/core/java/android/view/textclassifier/TextClassifierImpl.java
@@ -43,6 +43,8 @@
import com.android.internal.annotations.GuardedBy;
import com.android.internal.util.Preconditions;
+import com.google.android.textclassifier.AnnotatorModel;
+
import java.io.File;
import java.io.FileNotFoundException;
import java.io.IOException;
@@ -91,7 +93,7 @@
@GuardedBy("mLock") // Do not access outside this lock.
private ModelFile mModel;
@GuardedBy("mLock") // Do not access outside this lock.
- private TextClassifierImplNative mNative;
+ private AnnotatorModel mNative;
private final Object mLoggerLock = new Object();
@GuardedBy("mLoggerLock") // Do not access outside this lock.
@@ -124,7 +126,7 @@
&& rangeLength <= mSettings.getSuggestSelectionMaxRangeLength()) {
final String localesString = concatenateLocales(request.getDefaultLocales());
final ZonedDateTime refTime = ZonedDateTime.now();
- final TextClassifierImplNative nativeImpl = getNative(request.getDefaultLocales());
+ final AnnotatorModel nativeImpl = getNative(request.getDefaultLocales());
final int start;
final int end;
if (mSettings.isModelDarkLaunchEnabled() && !request.isDarkLaunchAllowed()) {
@@ -133,7 +135,7 @@
} else {
final int[] startEnd = nativeImpl.suggestSelection(
string, request.getStartIndex(), request.getEndIndex(),
- new TextClassifierImplNative.SelectionOptions(localesString));
+ new AnnotatorModel.SelectionOptions(localesString));
start = startEnd[0];
end = startEnd[1];
}
@@ -141,10 +143,10 @@
&& start >= 0 && end <= string.length()
&& start <= request.getStartIndex() && end >= request.getEndIndex()) {
final TextSelection.Builder tsBuilder = new TextSelection.Builder(start, end);
- final TextClassifierImplNative.ClassificationResult[] results =
+ final AnnotatorModel.ClassificationResult[] results =
nativeImpl.classifyText(
string, start, end,
- new TextClassifierImplNative.ClassificationOptions(
+ new AnnotatorModel.ClassificationOptions(
refTime.toInstant().toEpochMilli(),
refTime.getZone().getId(),
localesString));
@@ -183,11 +185,11 @@
final String localesString = concatenateLocales(request.getDefaultLocales());
final ZonedDateTime refTime = request.getReferenceTime() != null
? request.getReferenceTime() : ZonedDateTime.now();
- final TextClassifierImplNative.ClassificationResult[] results =
+ final AnnotatorModel.ClassificationResult[] results =
getNative(request.getDefaultLocales())
.classifyText(
string, request.getStartIndex(), request.getEndIndex(),
- new TextClassifierImplNative.ClassificationOptions(
+ new AnnotatorModel.ClassificationOptions(
refTime.toInstant().toEpochMilli(),
refTime.getZone().getId(),
localesString));
@@ -227,17 +229,17 @@
? request.getEntityConfig().resolveEntityListModifications(
getEntitiesForHints(request.getEntityConfig().getHints()))
: mSettings.getEntityListDefault();
- final TextClassifierImplNative nativeImpl =
+ final AnnotatorModel nativeImpl =
getNative(request.getDefaultLocales());
- final TextClassifierImplNative.AnnotatedSpan[] annotations =
+ final AnnotatorModel.AnnotatedSpan[] annotations =
nativeImpl.annotate(
textString,
- new TextClassifierImplNative.AnnotationOptions(
+ new AnnotatorModel.AnnotationOptions(
refTime.toInstant().toEpochMilli(),
refTime.getZone().getId(),
concatenateLocales(request.getDefaultLocales())));
- for (TextClassifierImplNative.AnnotatedSpan span : annotations) {
- final TextClassifierImplNative.ClassificationResult[] results =
+ for (AnnotatorModel.AnnotatedSpan span : annotations) {
+ final AnnotatorModel.ClassificationResult[] results =
span.getClassification();
if (results.length == 0
|| !entitiesToIdentify.contains(results[0].getCollection())) {
@@ -296,7 +298,7 @@
}
}
- private TextClassifierImplNative getNative(LocaleList localeList)
+ private AnnotatorModel getNative(LocaleList localeList)
throws FileNotFoundException {
synchronized (mLock) {
localeList = localeList == null ? LocaleList.getEmptyLocaleList() : localeList;
@@ -309,7 +311,7 @@
destroyNativeIfExistsLocked();
final ParcelFileDescriptor fd = ParcelFileDescriptor.open(
new File(bestModel.getPath()), ParcelFileDescriptor.MODE_READ_ONLY);
- mNative = new TextClassifierImplNative(fd.getFd());
+ mNative = new AnnotatorModel(fd.getFd());
closeAndLogError(fd);
mModel = bestModel;
}
@@ -397,14 +399,14 @@
}
private TextClassification createClassificationResult(
- TextClassifierImplNative.ClassificationResult[] classifications,
+ AnnotatorModel.ClassificationResult[] classifications,
String text, int start, int end, @Nullable Instant referenceTime) {
final String classifiedText = text.substring(start, end);
final TextClassification.Builder builder = new TextClassification.Builder()
.setText(classifiedText);
final int size = classifications.length;
- TextClassifierImplNative.ClassificationResult highestScoringResult = null;
+ AnnotatorModel.ClassificationResult highestScoringResult = null;
float highestScore = Float.MIN_VALUE;
for (int i = 0; i < size; i++) {
builder.setEntityType(classifications[i].getCollection(),
@@ -467,9 +469,9 @@
try {
final ParcelFileDescriptor modelFd = ParcelFileDescriptor.open(
file, ParcelFileDescriptor.MODE_READ_ONLY);
- final int version = TextClassifierImplNative.getVersion(modelFd.getFd());
+ final int version = AnnotatorModel.getVersion(modelFd.getFd());
final String supportedLocalesStr =
- TextClassifierImplNative.getLocales(modelFd.getFd());
+ AnnotatorModel.getLocales(modelFd.getFd());
if (supportedLocalesStr.isEmpty()) {
Log.d(DEFAULT_LOG_TAG, "Ignoring " + file.getAbsolutePath());
return null;
@@ -657,7 +659,7 @@
public static List<LabeledIntent> create(
Context context,
@Nullable Instant referenceTime,
- TextClassifierImplNative.ClassificationResult classification,
+ AnnotatorModel.ClassificationResult classification,
String text) {
final String type = classification.getCollection().trim().toLowerCase(Locale.ENGLISH);
text = text.trim();
diff --git a/core/java/android/view/textclassifier/TextClassifierImplNative.java b/core/java/android/view/textclassifier/TextClassifierImplNative.java
deleted file mode 100644
index 3d4c8f2..0000000
--- a/core/java/android/view/textclassifier/TextClassifierImplNative.java
+++ /dev/null
@@ -1,301 +0,0 @@
-/*
- * Copyright (C) 2017 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.view.textclassifier;
-
-import android.content.res.AssetFileDescriptor;
-
-/**
- * Java wrapper for TextClassifier native library interface. This library is used for detecting
- * entities in text.
- */
-final class TextClassifierImplNative {
-
- static {
- System.loadLibrary("textclassifier");
- }
-
- private final long mModelPtr;
-
- /**
- * Creates a new instance of TextClassifierImplNative, using the provided model image, given as
- * a file descriptor.
- */
- TextClassifierImplNative(int fd) {
- mModelPtr = nativeNew(fd);
- if (mModelPtr == 0L) {
- throw new IllegalArgumentException("Couldn't initialize TC from file descriptor.");
- }
- }
-
- /**
- * Creates a new instance of TextClassifierImplNative, using the provided model image, given as
- * a file path.
- */
- TextClassifierImplNative(String path) {
- mModelPtr = nativeNewFromPath(path);
- if (mModelPtr == 0L) {
- throw new IllegalArgumentException("Couldn't initialize TC from given file.");
- }
- }
-
- /**
- * Creates a new instance of TextClassifierImplNative, using the provided model image, given as
- * an AssetFileDescriptor.
- */
- TextClassifierImplNative(AssetFileDescriptor afd) {
- mModelPtr = nativeNewFromAssetFileDescriptor(afd, afd.getStartOffset(), afd.getLength());
- if (mModelPtr == 0L) {
- throw new IllegalArgumentException(
- "Couldn't initialize TC from given AssetFileDescriptor");
- }
- }
-
- /**
- * Given a string context and current selection, computes the SmartSelection suggestion.
- *
- * <p>The begin and end are character indices into the context UTF8 string. selectionBegin is
- * the character index where the selection begins, and selectionEnd is the index of one
- * character past the selection span.
- *
- * <p>The return value is an array of two ints: suggested selection beginning and end, with the
- * same semantics as the input selectionBeginning and selectionEnd.
- */
- public int[] suggestSelection(
- String context, int selectionBegin, int selectionEnd, SelectionOptions options) {
- return nativeSuggestSelection(mModelPtr, context, selectionBegin, selectionEnd, options);
- }
-
- /**
- * Given a string context and current selection, classifies the type of the selected text.
- *
- * <p>The begin and end params are character indices in the context string.
- *
- * <p>Returns an array of ClassificationResult objects with the probability scores for different
- * collections.
- */
- public ClassificationResult[] classifyText(
- String context, int selectionBegin, int selectionEnd, ClassificationOptions options) {
- return nativeClassifyText(mModelPtr, context, selectionBegin, selectionEnd, options);
- }
-
- /**
- * Annotates given input text. The annotations should cover the whole input context except for
- * whitespaces, and are sorted by their position in the context string.
- */
- public AnnotatedSpan[] annotate(String text, AnnotationOptions options) {
- return nativeAnnotate(mModelPtr, text, options);
- }
-
- /** Frees up the allocated memory. */
- public void close() {
- nativeClose(mModelPtr);
- }
-
- /** Returns a comma separated list of locales supported by the model as BCP 47 tags. */
- public static String getLocales(int fd) {
- return nativeGetLocales(fd);
- }
-
- /** Returns the version of the model. */
- public static int getVersion(int fd) {
- return nativeGetVersion(fd);
- }
-
- /** Represents a datetime parsing result from classifyText calls. */
- public static final class DatetimeResult {
- static final int GRANULARITY_YEAR = 0;
- static final int GRANULARITY_MONTH = 1;
- static final int GRANULARITY_WEEK = 2;
- static final int GRANULARITY_DAY = 3;
- static final int GRANULARITY_HOUR = 4;
- static final int GRANULARITY_MINUTE = 5;
- static final int GRANULARITY_SECOND = 6;
-
- private final long mTimeMsUtc;
- private final int mGranularity;
-
- DatetimeResult(long timeMsUtc, int granularity) {
- mGranularity = granularity;
- mTimeMsUtc = timeMsUtc;
- }
-
- public long getTimeMsUtc() {
- return mTimeMsUtc;
- }
-
- public int getGranularity() {
- return mGranularity;
- }
- }
-
- /** Represents a result of classifyText method call. */
- public static final class ClassificationResult {
- private final String mCollection;
- private final float mScore;
- private final DatetimeResult mDatetimeResult;
-
- ClassificationResult(
- String collection, float score, DatetimeResult datetimeResult) {
- mCollection = collection;
- mScore = score;
- mDatetimeResult = datetimeResult;
- }
-
- public String getCollection() {
- if (mCollection.equals(TextClassifier.TYPE_DATE) && mDatetimeResult != null) {
- switch (mDatetimeResult.getGranularity()) {
- case DatetimeResult.GRANULARITY_HOUR:
- // fall through
- case DatetimeResult.GRANULARITY_MINUTE:
- // fall through
- case DatetimeResult.GRANULARITY_SECOND:
- return TextClassifier.TYPE_DATE_TIME;
- default:
- return TextClassifier.TYPE_DATE;
- }
- }
- return mCollection;
- }
-
- public float getScore() {
- return mScore;
- }
-
- public DatetimeResult getDatetimeResult() {
- return mDatetimeResult;
- }
- }
-
- /** Represents a result of Annotate call. */
- public static final class AnnotatedSpan {
- private final int mStartIndex;
- private final int mEndIndex;
- private final ClassificationResult[] mClassification;
-
- AnnotatedSpan(
- int startIndex, int endIndex, ClassificationResult[] classification) {
- mStartIndex = startIndex;
- mEndIndex = endIndex;
- mClassification = classification;
- }
-
- public int getStartIndex() {
- return mStartIndex;
- }
-
- public int getEndIndex() {
- return mEndIndex;
- }
-
- public ClassificationResult[] getClassification() {
- return mClassification;
- }
- }
-
- /** Represents options for the suggestSelection call. */
- public static final class SelectionOptions {
- private final String mLocales;
-
- SelectionOptions(String locales) {
- mLocales = locales;
- }
-
- public String getLocales() {
- return mLocales;
- }
- }
-
- /** Represents options for the classifyText call. */
- public static final class ClassificationOptions {
- private final long mReferenceTimeMsUtc;
- private final String mReferenceTimezone;
- private final String mLocales;
-
- ClassificationOptions(long referenceTimeMsUtc, String referenceTimezone, String locale) {
- mReferenceTimeMsUtc = referenceTimeMsUtc;
- mReferenceTimezone = referenceTimezone;
- mLocales = locale;
- }
-
- public long getReferenceTimeMsUtc() {
- return mReferenceTimeMsUtc;
- }
-
- public String getReferenceTimezone() {
- return mReferenceTimezone;
- }
-
- public String getLocale() {
- return mLocales;
- }
- }
-
- /** Represents options for the Annotate call. */
- public static final class AnnotationOptions {
- private final long mReferenceTimeMsUtc;
- private final String mReferenceTimezone;
- private final String mLocales;
-
- AnnotationOptions(long referenceTimeMsUtc, String referenceTimezone, String locale) {
- mReferenceTimeMsUtc = referenceTimeMsUtc;
- mReferenceTimezone = referenceTimezone;
- mLocales = locale;
- }
-
- public long getReferenceTimeMsUtc() {
- return mReferenceTimeMsUtc;
- }
-
- public String getReferenceTimezone() {
- return mReferenceTimezone;
- }
-
- public String getLocale() {
- return mLocales;
- }
- }
-
- private static native long nativeNew(int fd);
-
- private static native long nativeNewFromPath(String path);
-
- private static native long nativeNewFromAssetFileDescriptor(
- AssetFileDescriptor afd, long offset, long size);
-
- private static native int[] nativeSuggestSelection(
- long context,
- String text,
- int selectionBegin,
- int selectionEnd,
- SelectionOptions options);
-
- private static native ClassificationResult[] nativeClassifyText(
- long context,
- String text,
- int selectionBegin,
- int selectionEnd,
- ClassificationOptions options);
-
- private static native AnnotatedSpan[] nativeAnnotate(
- long context, String text, AnnotationOptions options);
-
- private static native void nativeClose(long context);
-
- private static native String nativeGetLocales(int fd);
-
- private static native int nativeGetVersion(int fd);
-}
diff --git a/data/etc/platform.xml b/data/etc/platform.xml
index 73c10d2..afe7913 100644
--- a/data/etc/platform.xml
+++ b/data/etc/platform.xml
@@ -182,11 +182,11 @@
code to link against. -->
<library name="android.test.base"
- file="/system/framework/android.test.base.impl.jar" />
+ file="/system/framework/android.test.base.jar" />
<library name="android.test.mock"
- file="/system/framework/android.test.mock.impl.jar" />
+ file="/system/framework/android.test.mock.jar" />
<library name="android.test.runner"
- file="/system/framework/android.test.runner.impl.jar" />
+ file="/system/framework/android.test.runner.jar" />
<!-- In BOOT_JARS historically, and now added to legacy applications. -->
<library name="android.hidl.base-V1.0-java"
diff --git a/services/core/java/com/android/server/camera/CameraServiceProxy.java b/services/core/java/com/android/server/camera/CameraServiceProxy.java
index 0ee55ed..527539d 100644
--- a/services/core/java/com/android/server/camera/CameraServiceProxy.java
+++ b/services/core/java/com/android/server/camera/CameraServiceProxy.java
@@ -21,6 +21,7 @@
import android.content.IntentFilter;
import android.hardware.ICameraService;
import android.hardware.ICameraServiceProxy;
+import android.media.AudioManager;
import android.metrics.LogMaker;
import android.nfc.INfcAdapter;
import android.os.Binder;
@@ -393,6 +394,19 @@
boolean wasEmpty = mActiveCameraUsage.isEmpty();
switch (newCameraState) {
case ICameraServiceProxy.CAMERA_STATE_OPEN:
+ // Notify the audio subsystem about the facing of the most-recently opened
+ // camera This can be used to select the best audio tuning in case video
+ // recording with that camera will happen. Since only open events are used, if
+ // multiple cameras are opened at once, the one opened last will be used to
+ // select audio tuning.
+ AudioManager audioManager = getContext().getSystemService(AudioManager.class);
+ if (audioManager != null) {
+ // Map external to front for audio tuning purposes
+ String facingStr = (facing == ICameraServiceProxy.CAMERA_FACING_BACK) ?
+ "back" : "front";
+ String facingParameter = "cameraFacing=" + facingStr;
+ audioManager.setParameters(facingParameter);
+ }
break;
case ICameraServiceProxy.CAMERA_STATE_ACTIVE:
CameraUsageEvent newEvent = new CameraUsageEvent(facing, clientName, apiLevel);
diff --git a/services/core/java/com/android/server/connectivity/PacManager.java b/services/core/java/com/android/server/connectivity/PacManager.java
index 3ea9810..9789688 100644
--- a/services/core/java/com/android/server/connectivity/PacManager.java
+++ b/services/core/java/com/android/server/connectivity/PacManager.java
@@ -282,6 +282,7 @@
private void setCurrentProxyScript(String script) {
if (mProxyService == null) {
Log.e(TAG, "setCurrentProxyScript: no proxy service");
+ return;
}
try {
mProxyService.setPacFile(script);
diff --git a/services/net/java/android/net/shared/LinkPropertiesParcelableUtil.java b/services/net/java/android/net/shared/LinkPropertiesParcelableUtil.java
new file mode 100644
index 0000000..5b77f54
--- /dev/null
+++ b/services/net/java/android/net/shared/LinkPropertiesParcelableUtil.java
@@ -0,0 +1,222 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.net.shared;
+
+import static android.net.shared.ParcelableUtil.fromParcelableArray;
+import static android.net.shared.ParcelableUtil.toParcelableArray;
+
+import android.annotation.Nullable;
+import android.net.InetAddresses;
+import android.net.IpPrefix;
+import android.net.IpPrefixParcelable;
+import android.net.LinkAddress;
+import android.net.LinkAddressParcelable;
+import android.net.LinkProperties;
+import android.net.LinkPropertiesParcelable;
+import android.net.ProxyInfo;
+import android.net.ProxyInfoParcelable;
+import android.net.RouteInfo;
+import android.net.RouteInfoParcelable;
+import android.net.Uri;
+
+import java.net.InetAddress;
+import java.util.Arrays;
+
+/**
+ * Collection of utility methods to convert to and from stable AIDL parcelables for LinkProperties
+ * and its attributes.
+ * @hide
+ */
+public final class LinkPropertiesParcelableUtil {
+
+ /**
+ * Convert a ProxyInfo to a ProxyInfoParcelable
+ */
+ public static ProxyInfoParcelable toStableParcelable(@Nullable ProxyInfo proxyInfo) {
+ if (proxyInfo == null) {
+ return null;
+ }
+ final ProxyInfoParcelable parcel = new ProxyInfoParcelable();
+ parcel.host = proxyInfo.getHost();
+ parcel.port = proxyInfo.getPort();
+ parcel.exclusionList = proxyInfo.getExclusionList();
+ parcel.pacFileUrl = proxyInfo.getPacFileUrl().toString();
+ return parcel;
+ }
+
+ /**
+ * Convert a ProxyInfoParcelable to a ProxyInfo
+ */
+ public static ProxyInfo fromStableParcelable(@Nullable ProxyInfoParcelable parcel) {
+ if (parcel == null) {
+ return null;
+ }
+ if (Uri.EMPTY.toString().equals(parcel.pacFileUrl)) {
+ return ProxyInfo.buildDirectProxy(
+ parcel.host, parcel.port, Arrays.asList(parcel.exclusionList));
+ } else {
+ return ProxyInfo.buildPacProxy(Uri.parse(parcel.pacFileUrl));
+ }
+ }
+
+ /**
+ * Convert an IpPrefixParcelable to an IpPrefix
+ */
+ public static IpPrefixParcelable toStableParcelable(@Nullable IpPrefix ipPrefix) {
+ if (ipPrefix == null) {
+ return null;
+ }
+ final IpPrefixParcelable parcel = new IpPrefixParcelable();
+ parcel.address = ipPrefix.getAddress().getHostAddress();
+ parcel.prefixLength = ipPrefix.getPrefixLength();
+ return parcel;
+ }
+
+ /**
+ * Convert an IpPrefix to an IpPrefixParcelable
+ */
+ public static IpPrefix fromStableParcelable(@Nullable IpPrefixParcelable parcel) {
+ if (parcel == null) {
+ return null;
+ }
+ return new IpPrefix(InetAddresses.parseNumericAddress(parcel.address), parcel.prefixLength);
+ }
+
+ /**
+ * Convert a RouteInfoParcelable to a RouteInfo
+ */
+ public static RouteInfoParcelable toStableParcelable(@Nullable RouteInfo routeInfo) {
+ if (routeInfo == null) {
+ return null;
+ }
+ final RouteInfoParcelable parcel = new RouteInfoParcelable();
+ parcel.destination = toStableParcelable(routeInfo.getDestination());
+ parcel.gatewayAddr = routeInfo.getGateway().getHostAddress();
+ parcel.ifaceName = routeInfo.getInterface();
+ parcel.type = routeInfo.getType();
+ return parcel;
+ }
+
+ /**
+ * Convert a RouteInfo to a RouteInfoParcelable
+ */
+ public static RouteInfo fromStableParcelable(@Nullable RouteInfoParcelable parcel) {
+ if (parcel == null) {
+ return null;
+ }
+ final IpPrefix destination = fromStableParcelable(parcel.destination);
+ return new RouteInfo(
+ destination, InetAddresses.parseNumericAddress(parcel.gatewayAddr),
+ parcel.ifaceName, parcel.type);
+ }
+
+ /**
+ * Convert a LinkAddressParcelable to a LinkAddress
+ */
+ public static LinkAddressParcelable toStableParcelable(@Nullable LinkAddress la) {
+ if (la == null) {
+ return null;
+ }
+ final LinkAddressParcelable parcel = new LinkAddressParcelable();
+ parcel.address = la.getAddress().getHostAddress();
+ parcel.prefixLength = la.getPrefixLength();
+ parcel.flags = la.getFlags();
+ parcel.scope = la.getScope();
+ return parcel;
+ }
+
+ /**
+ * Convert a LinkAddress to a LinkAddressParcelable
+ */
+ public static LinkAddress fromStableParcelable(@Nullable LinkAddressParcelable parcel) {
+ if (parcel == null) {
+ return null;
+ }
+ return new LinkAddress(
+ InetAddresses.parseNumericAddress(parcel.address),
+ parcel.prefixLength,
+ parcel.flags,
+ parcel.scope);
+ }
+
+ /**
+ * Convert a LinkProperties to a LinkPropertiesParcelable
+ */
+ public static LinkPropertiesParcelable toStableParcelable(@Nullable LinkProperties lp) {
+ if (lp == null) {
+ return null;
+ }
+ final LinkPropertiesParcelable parcel = new LinkPropertiesParcelable();
+ parcel.ifaceName = lp.getInterfaceName();
+ parcel.linkAddresses = toParcelableArray(
+ lp.getLinkAddresses(),
+ LinkPropertiesParcelableUtil::toStableParcelable,
+ LinkAddressParcelable.class);
+ parcel.dnses = toParcelableArray(
+ lp.getDnsServers(), InetAddress::getHostAddress, String.class);
+ parcel.pcscfs = toParcelableArray(
+ lp.getPcscfServers(), InetAddress::getHostAddress, String.class);
+ parcel.validatedPrivateDnses = toParcelableArray(
+ lp.getValidatedPrivateDnsServers(), InetAddress::getHostAddress, String.class);
+ parcel.usePrivateDns = lp.isPrivateDnsActive();
+ parcel.privateDnsServerName = lp.getPrivateDnsServerName();
+ parcel.domains = lp.getDomains();
+ parcel.routes = toParcelableArray(
+ lp.getRoutes(), LinkPropertiesParcelableUtil::toStableParcelable,
+ RouteInfoParcelable.class);
+ parcel.httpProxy = toStableParcelable(lp.getHttpProxy());
+ parcel.mtu = lp.getMtu();
+ parcel.tcpBufferSizes = lp.getTcpBufferSizes();
+ parcel.nat64Prefix = toStableParcelable(lp.getNat64Prefix());
+ parcel.stackedLinks = toParcelableArray(
+ lp.getStackedLinks(), LinkPropertiesParcelableUtil::toStableParcelable,
+ LinkPropertiesParcelable.class);
+ return parcel;
+ }
+
+ /**
+ * Convert a LinkPropertiesParcelable to a LinkProperties
+ */
+ public static LinkProperties fromStableParcelable(@Nullable LinkPropertiesParcelable parcel) {
+ if (parcel == null) {
+ return null;
+ }
+ final LinkProperties lp = new LinkProperties();
+ lp.setInterfaceName(parcel.ifaceName);
+ lp.setLinkAddresses(fromParcelableArray(parcel.linkAddresses,
+ LinkPropertiesParcelableUtil::fromStableParcelable));
+ lp.setDnsServers(fromParcelableArray(parcel.dnses, InetAddresses::parseNumericAddress));
+ lp.setPcscfServers(fromParcelableArray(parcel.pcscfs, InetAddresses::parseNumericAddress));
+ lp.setValidatedPrivateDnsServers(
+ fromParcelableArray(parcel.validatedPrivateDnses,
+ InetAddresses::parseNumericAddress));
+ lp.setUsePrivateDns(parcel.usePrivateDns);
+ lp.setPrivateDnsServerName(parcel.privateDnsServerName);
+ lp.setDomains(parcel.domains);
+ for (RouteInfoParcelable route : parcel.routes) {
+ lp.addRoute(fromStableParcelable(route));
+ }
+ lp.setHttpProxy(fromStableParcelable(parcel.httpProxy));
+ lp.setMtu(parcel.mtu);
+ lp.setTcpBufferSizes(parcel.tcpBufferSizes);
+ lp.setNat64Prefix(fromStableParcelable(parcel.nat64Prefix));
+ for (LinkPropertiesParcelable stackedLink : parcel.stackedLinks) {
+ lp.addStackedLink(fromStableParcelable(stackedLink));
+ }
+ return lp;
+ }
+}
diff --git a/services/net/java/android/net/shared/ParcelableUtil.java b/services/net/java/android/net/shared/ParcelableUtil.java
new file mode 100644
index 0000000..a18976c
--- /dev/null
+++ b/services/net/java/android/net/shared/ParcelableUtil.java
@@ -0,0 +1,63 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.net.shared;
+
+import android.annotation.NonNull;
+
+import java.lang.reflect.Array;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.function.Function;
+
+/**
+ * Utility methods to help convert to/from stable parcelables.
+ * @hide
+ */
+public final class ParcelableUtil {
+ // Below methods could be implemented easily with streams, but streams are frowned upon in
+ // frameworks code.
+
+ /**
+ * Convert a list of BaseType items to an array of ParcelableType items using the specified
+ * converter function.
+ */
+ public static <ParcelableType, BaseType> ParcelableType[] toParcelableArray(
+ @NonNull List<BaseType> base,
+ @NonNull Function<BaseType, ParcelableType> conv,
+ @NonNull Class<ParcelableType> parcelClass) {
+ final ParcelableType[] out = (ParcelableType[]) Array.newInstance(parcelClass, base.size());
+ int i = 0;
+ for (BaseType b : base) {
+ out[i] = conv.apply(b);
+ i++;
+ }
+ return out;
+ }
+
+ /**
+ * Convert an array of ParcelableType items to a list of BaseType items using the specified
+ * converter function.
+ */
+ public static <ParcelableType, BaseType> ArrayList<BaseType> fromParcelableArray(
+ @NonNull ParcelableType[] parceled, @NonNull Function<ParcelableType, BaseType> conv) {
+ final ArrayList<BaseType> out = new ArrayList<>(parceled.length);
+ for (ParcelableType t : parceled) {
+ out.add(conv.apply(t));
+ }
+ return out;
+ }
+}
diff --git a/telecomm/java/android/telecom/CallRedirectionService.java b/telecomm/java/android/telecom/CallRedirectionService.java
index b906d0b..3299117 100644
--- a/telecomm/java/android/telecom/CallRedirectionService.java
+++ b/telecomm/java/android/telecom/CallRedirectionService.java
@@ -16,6 +16,7 @@
package android.telecom;
+import android.annotation.NonNull;
import android.annotation.SdkConstant;
import android.app.Service;
import android.content.Intent;
@@ -27,8 +28,8 @@
import android.os.RemoteException;
import com.android.internal.os.SomeArgs;
-import com.android.internal.telecom.ICallRedirectionService;
import com.android.internal.telecom.ICallRedirectionAdapter;
+import com.android.internal.telecom.ICallRedirectionService;
/**
* This service can be implemented to interact between Telecom and its implementor
@@ -62,22 +63,35 @@
/**
* Telecom calls this method to inform the implemented {@link CallRedirectionService} of
- * a new outgoing call which is being placed.
+ * a new outgoing call which is being placed. Telecom does not request to redirect emergency
+ * calls and does not request to redirect calls with gateway information.
*
- * The implemented {@link CallRedirectionService} can call {@link #placeCallUnmodified()},
- * {@link #redirectCall(Uri, PhoneAccountHandle)}, and {@link #cancelCall()} only from here.
+ * <p>Telecom will cancel the call if Telecom does not receive a response in 5 seconds from
+ * the implemented {@link CallRedirectionService} set by users.
*
- * @param handle the phone number dialed by the user
- * @param targetPhoneAccount the {@link PhoneAccountHandle} on which the call will be placed.
+ * <p>The implemented {@link CallRedirectionService} can call {@link #placeCallUnmodified()},
+ * {@link #redirectCall(Uri, PhoneAccountHandle, boolean)}, and {@link #cancelCall()} only
+ * from here.
+ *
+ * @param handle the phone number dialed by the user, represented in E.164 format if possible
+ * @param initialPhoneAccount the {@link PhoneAccountHandle} on which the call will be placed.
+ * @param allowInteractiveResponse a boolean to tell if the implemented
+ * {@link CallRedirectionService} should allow interactive
+ * responses with users. Will be {@code false} if, for example
+ * the device is in car mode and the user would not be able to
+ * interact with their device.
*/
- public abstract void onPlaceCall(Uri handle, PhoneAccountHandle targetPhoneAccount);
+ public abstract void onPlaceCall(@NonNull Uri handle,
+ @NonNull PhoneAccountHandle initialPhoneAccount,
+ boolean allowInteractiveResponse);
/**
* The implemented {@link CallRedirectionService} calls this method to response a request
- * received via {@link #onPlaceCall(Uri, PhoneAccountHandle)} to inform Telecom that no changes
- * are required to the outgoing call, and that the call should be placed as-is.
+ * received via {@link #onPlaceCall(Uri, PhoneAccountHandle, boolean)} to inform Telecom that
+ * no changes are required to the outgoing call, and that the call should be placed as-is.
*
- * This can only be called from implemented {@link #onPlaceCall(Uri, PhoneAccountHandle)}.
+ * <p>This can only be called from implemented
+ * {@link #onPlaceCall(Uri, PhoneAccountHandle, boolean)}.
*
*/
public final void placeCallUnmodified() {
@@ -89,29 +103,39 @@
/**
* The implemented {@link CallRedirectionService} calls this method to response a request
- * received via {@link #onPlaceCall(Uri, PhoneAccountHandle)} to inform Telecom that changes
- * are required to the phone number or/and {@link PhoneAccountHandle} for the outgoing call.
+ * received via {@link #onPlaceCall(Uri, PhoneAccountHandle, boolean)} to inform Telecom that
+ * changes are required to the phone number or/and {@link PhoneAccountHandle} for the outgoing
+ * call. Telecom will cancel the call if the implemented {@link CallRedirectionService}
+ * replies Telecom a handle for an emergency number.
*
- * This can only be called from implemented {@link #onPlaceCall(Uri, PhoneAccountHandle)}.
+ * <p>This can only be called from implemented
+ * {@link #onPlaceCall(Uri, PhoneAccountHandle, boolean)}.
*
* @param handle the new phone number to dial
* @param targetPhoneAccount the {@link PhoneAccountHandle} to use when placing the call.
* If {@code null}, no change will be made to the
* {@link PhoneAccountHandle} used to place the call.
+ * @param confirmFirst Telecom will ask users to confirm the redirection via a yes/no dialog
+ * if the confirmFirst is true, and if the redirection request of this
+ * response was sent with a true flag of allowInteractiveResponse via
+ * {@link #onPlaceCall(Uri, PhoneAccountHandle, boolean)}
*/
- public final void redirectCall(Uri handle, PhoneAccountHandle targetPhoneAccount) {
+ public final void redirectCall(@NonNull Uri handle,
+ @NonNull PhoneAccountHandle targetPhoneAccount,
+ boolean confirmFirst) {
try {
- mCallRedirectionAdapter.redirectCall(handle, targetPhoneAccount);
+ mCallRedirectionAdapter.redirectCall(handle, targetPhoneAccount, confirmFirst);
} catch (RemoteException e) {
}
}
/**
* The implemented {@link CallRedirectionService} calls this method to response a request
- * received via {@link #onPlaceCall(Uri, PhoneAccountHandle)} to inform Telecom that an outgoing
- * call should be canceled entirely.
+ * received via {@link #onPlaceCall(Uri, PhoneAccountHandle, boolean)} to inform Telecom that
+ * an outgoing call should be canceled entirely.
*
- * This can only be called from implemented {@link #onPlaceCall(Uri, PhoneAccountHandle)}.
+ * <p>This can only be called from implemented
+ * {@link #onPlaceCall(Uri, PhoneAccountHandle, boolean)}.
*
*/
public final void cancelCall() {
@@ -137,7 +161,8 @@
SomeArgs args = (SomeArgs) msg.obj;
try {
mCallRedirectionAdapter = (ICallRedirectionAdapter) args.arg1;
- onPlaceCall((Uri) args.arg2, (PhoneAccountHandle) args.arg3);
+ onPlaceCall((Uri) args.arg2, (PhoneAccountHandle) args.arg3,
+ (boolean) args.arg4);
} finally {
args.recycle();
}
@@ -152,15 +177,20 @@
* Telecom calls this method to inform the CallRedirectionService of a new outgoing call
* which is about to be placed.
* @param handle the phone number dialed by the user
- * @param targetPhoneAccount the URI of the number the user dialed
+ * @param initialPhoneAccount the URI of the number the user dialed
+ * @param allowInteractiveResponse a boolean to tell if the implemented
+ * {@link CallRedirectionService} should allow interactive
+ * responses with users.
*/
@Override
- public void placeCall(ICallRedirectionAdapter adapter, Uri handle,
- PhoneAccountHandle targetPhoneAccount) {
+ public void placeCall(@NonNull ICallRedirectionAdapter adapter, @NonNull Uri handle,
+ @NonNull PhoneAccountHandle initialPhoneAccount,
+ boolean allowInteractiveResponse) {
SomeArgs args = SomeArgs.obtain();
args.arg1 = adapter;
args.arg2 = handle;
- args.arg3 = targetPhoneAccount;
+ args.arg3 = initialPhoneAccount;
+ args.arg4 = allowInteractiveResponse;
mHandler.obtainMessage(MSG_PLACE_CALL, args).sendToTarget();
}
}
diff --git a/telecomm/java/com/android/internal/telecom/ICallRedirectionAdapter.aidl b/telecomm/java/com/android/internal/telecom/ICallRedirectionAdapter.aidl
index 46bf983..0a42a3f 100644
--- a/telecomm/java/com/android/internal/telecom/ICallRedirectionAdapter.aidl
+++ b/telecomm/java/com/android/internal/telecom/ICallRedirectionAdapter.aidl
@@ -31,5 +31,6 @@
void placeCallUnmodified();
- void redirectCall(in Uri handle, in PhoneAccountHandle targetPhoneAccount);
+ void redirectCall(in Uri handle, in PhoneAccountHandle targetPhoneAccount,
+ boolean confirmFirst);
}
diff --git a/telecomm/java/com/android/internal/telecom/ICallRedirectionService.aidl b/telecomm/java/com/android/internal/telecom/ICallRedirectionService.aidl
index d8d360b..c1bc440 100644
--- a/telecomm/java/com/android/internal/telecom/ICallRedirectionService.aidl
+++ b/telecomm/java/com/android/internal/telecom/ICallRedirectionService.aidl
@@ -30,5 +30,5 @@
*/
oneway interface ICallRedirectionService {
void placeCall(in ICallRedirectionAdapter adapter, in Uri handle,
- in PhoneAccountHandle targetPhoneAccount);
+ in PhoneAccountHandle initialPhoneAccount, boolean allowInteractiveResponse);
}
diff --git a/telephony/java/android/telephony/CellConfigLte.java b/telephony/java/android/telephony/CellConfigLte.java
index 35769f0..eafbfbc 100644
--- a/telephony/java/android/telephony/CellConfigLte.java
+++ b/telephony/java/android/telephony/CellConfigLte.java
@@ -34,6 +34,11 @@
}
/** @hide */
+ public CellConfigLte(android.hardware.radio.V1_4.CellConfigLte cellConfig) {
+ mIsEndcAvailable = cellConfig.isEndcAvailable;
+ }
+
+ /** @hide */
public CellConfigLte(boolean isEndcAvailable) {
mIsEndcAvailable = isEndcAvailable;
}
diff --git a/telephony/java/android/telephony/CellInfo.java b/telephony/java/android/telephony/CellInfo.java
index b761bd7..8ce5c54 100644
--- a/telephony/java/android/telephony/CellInfo.java
+++ b/telephony/java/android/telephony/CellInfo.java
@@ -19,8 +19,10 @@
import android.annotation.IntDef;
import android.annotation.NonNull;
import android.annotation.UnsupportedAppUsage;
+import android.hardware.radio.V1_4.CellInfo.Info;
import android.os.Parcel;
import android.os.Parcelable;
+import android.os.SystemClock;
import com.android.internal.annotations.VisibleForTesting;
@@ -318,6 +320,13 @@
}
/** @hide */
+ protected CellInfo(android.hardware.radio.V1_4.CellInfo ci) {
+ this.mRegistered = ci.isRegistered;
+ this.mTimeStamp = SystemClock.elapsedRealtimeNanos();
+ this.mCellConnectionStatus = ci.connectionStatus;
+ }
+
+ /** @hide */
public static CellInfo create(android.hardware.radio.V1_0.CellInfo ci) {
if (ci == null) return null;
switch(ci.cellInfoType) {
@@ -342,4 +351,17 @@
default: return null;
}
}
+
+ /** @hide */
+ public static CellInfo create(android.hardware.radio.V1_4.CellInfo ci) {
+ if (ci == null) return null;
+ switch (ci.info.getDiscriminator()) {
+ case Info.hidl_discriminator.gsm: return new CellInfoGsm(ci);
+ case Info.hidl_discriminator.cdma: return new CellInfoCdma(ci);
+ case Info.hidl_discriminator.lte: return new CellInfoLte(ci);
+ case Info.hidl_discriminator.wcdma: return new CellInfoWcdma(ci);
+ case Info.hidl_discriminator.tdscdma: return new CellInfoTdscdma(ci);
+ default: return null;
+ }
+ }
}
diff --git a/telephony/java/android/telephony/CellInfoCdma.java b/telephony/java/android/telephony/CellInfoCdma.java
index c9f07da..4440108 100644
--- a/telephony/java/android/telephony/CellInfoCdma.java
+++ b/telephony/java/android/telephony/CellInfoCdma.java
@@ -67,6 +67,15 @@
new CellSignalStrengthCdma(cic.signalStrengthCdma, cic.signalStrengthEvdo);
}
+ /** @hide */
+ public CellInfoCdma(android.hardware.radio.V1_4.CellInfo ci) {
+ super(ci);
+ final android.hardware.radio.V1_2.CellInfoCdma cic = ci.info.cdma();
+ mCellIdentityCdma = new CellIdentityCdma(cic.cellIdentityCdma);
+ mCellSignalStrengthCdma =
+ new CellSignalStrengthCdma(cic.signalStrengthCdma, cic.signalStrengthEvdo);
+ }
+
@Override
public CellIdentityCdma getCellIdentity() {
return mCellIdentityCdma;
diff --git a/telephony/java/android/telephony/CellInfoGsm.java b/telephony/java/android/telephony/CellInfoGsm.java
index ad16dfa..248adfc 100644
--- a/telephony/java/android/telephony/CellInfoGsm.java
+++ b/telephony/java/android/telephony/CellInfoGsm.java
@@ -63,6 +63,14 @@
mCellSignalStrengthGsm = new CellSignalStrengthGsm(cig.signalStrengthGsm);
}
+ /** @hide */
+ public CellInfoGsm(android.hardware.radio.V1_4.CellInfo ci) {
+ super(ci);
+ final android.hardware.radio.V1_2.CellInfoGsm cig = ci.info.gsm();
+ mCellIdentityGsm = new CellIdentityGsm(cig.cellIdentityGsm);
+ mCellSignalStrengthGsm = new CellSignalStrengthGsm(cig.signalStrengthGsm);
+ }
+
@Override
public CellIdentityGsm getCellIdentity() {
return mCellIdentityGsm;
diff --git a/telephony/java/android/telephony/CellInfoLte.java b/telephony/java/android/telephony/CellInfoLte.java
index 7593831..8e8ce8a 100644
--- a/telephony/java/android/telephony/CellInfoLte.java
+++ b/telephony/java/android/telephony/CellInfoLte.java
@@ -70,6 +70,15 @@
mCellConfig = new CellConfigLte();
}
+ /** @hide */
+ public CellInfoLte(android.hardware.radio.V1_4.CellInfo ci) {
+ super(ci);
+ final android.hardware.radio.V1_4.CellInfoLte cil = ci.info.lte();
+ mCellIdentityLte = new CellIdentityLte(cil.base.cellIdentityLte);
+ mCellSignalStrengthLte = new CellSignalStrengthLte(cil.base.signalStrengthLte);
+ mCellConfig = new CellConfigLte(cil.cellConfig);
+ }
+
@Override
public CellIdentityLte getCellIdentity() {
if (DBG) log("getCellIdentity: " + mCellIdentityLte);
diff --git a/telephony/java/android/telephony/CellInfoTdscdma.java b/telephony/java/android/telephony/CellInfoTdscdma.java
index a8c49b7..2ab38fb 100644
--- a/telephony/java/android/telephony/CellInfoTdscdma.java
+++ b/telephony/java/android/telephony/CellInfoTdscdma.java
@@ -64,6 +64,14 @@
mCellSignalStrengthTdscdma = new CellSignalStrengthTdscdma(cit.signalStrengthTdscdma);
}
+ /** @hide */
+ public CellInfoTdscdma(android.hardware.radio.V1_4.CellInfo ci) {
+ super(ci);
+ final android.hardware.radio.V1_2.CellInfoTdscdma cit = ci.info.tdscdma();
+ mCellIdentityTdscdma = new CellIdentityTdscdma(cit.cellIdentityTdscdma);
+ mCellSignalStrengthTdscdma = new CellSignalStrengthTdscdma(cit.signalStrengthTdscdma);
+ }
+
@Override public CellIdentityTdscdma getCellIdentity() {
return mCellIdentityTdscdma;
}
diff --git a/telephony/java/android/telephony/CellInfoWcdma.java b/telephony/java/android/telephony/CellInfoWcdma.java
index a427e80..65e0470 100644
--- a/telephony/java/android/telephony/CellInfoWcdma.java
+++ b/telephony/java/android/telephony/CellInfoWcdma.java
@@ -63,6 +63,14 @@
mCellSignalStrengthWcdma = new CellSignalStrengthWcdma(ciw.signalStrengthWcdma);
}
+ /** @hide */
+ public CellInfoWcdma(android.hardware.radio.V1_4.CellInfo ci) {
+ super(ci);
+ final android.hardware.radio.V1_2.CellInfoWcdma ciw = ci.info.wcdma();
+ mCellIdentityWcdma = new CellIdentityWcdma(ciw.cellIdentityWcdma);
+ mCellSignalStrengthWcdma = new CellSignalStrengthWcdma(ciw.signalStrengthWcdma);
+ }
+
@Override
public CellIdentityWcdma getCellIdentity() {
return mCellIdentityWcdma;
diff --git a/telephony/java/android/telephony/PhoneStateListener.java b/telephony/java/android/telephony/PhoneStateListener.java
index c816701..9fee593 100644
--- a/telephony/java/android/telephony/PhoneStateListener.java
+++ b/telephony/java/android/telephony/PhoneStateListener.java
@@ -805,9 +805,11 @@
PhoneStateListener psl = mPhoneStateListenerWeakRef.get();
if (psl == null) return;
- Binder.withCleanCallingIdentity(
- () -> mExecutor.execute(
- () -> psl.onDataConnectionStateChanged(state, networkType)));
+ Binder.withCleanCallingIdentity(() -> mExecutor.execute(
+ () -> {
+ psl.onDataConnectionStateChanged(state, networkType);
+ psl.onDataConnectionStateChanged(state);
+ }));
}
public void onDataActivity(int direction) {
diff --git a/telephony/java/android/telephony/data/ApnSetting.java b/telephony/java/android/telephony/data/ApnSetting.java
index 200b540..8d148c3 100644
--- a/telephony/java/android/telephony/data/ApnSetting.java
+++ b/telephony/java/android/telephony/data/ApnSetting.java
@@ -81,7 +81,7 @@
*/
public static final int TYPE_ALL = ApnTypes.ALL;
/** APN type for default data traffic. */
- public static final int TYPE_DEFAULT = ApnTypes.DEFAULT;
+ public static final int TYPE_DEFAULT = ApnTypes.DEFAULT | ApnTypes.HIPRI;
/** APN type for MMS traffic. */
public static final int TYPE_MMS = ApnTypes.MMS;
/** APN type for SUPL assisted GPS. */
@@ -1019,7 +1019,7 @@
return false;
}
// DEFAULT can handle HIPRI.
- if (hasApnType(type) || (type == TYPE_HIPRI && hasApnType(TYPE_DEFAULT))) {
+ if (hasApnType(type)) {
return true;
}
return false;
diff --git a/telephony/java/android/telephony/emergency/EmergencyNumber.java b/telephony/java/android/telephony/emergency/EmergencyNumber.java
index fe062d5..a94b163 100644
--- a/telephony/java/android/telephony/emergency/EmergencyNumber.java
+++ b/telephony/java/android/telephony/emergency/EmergencyNumber.java
@@ -29,6 +29,7 @@
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
+import java.util.Objects;
import java.util.Set;
/**
@@ -198,21 +199,53 @@
EMERGENCY_NUMBER_SOURCE_SET.add(EMERGENCY_NUMBER_SOURCE_DEFAULT);
}
+ /**
+ * Indicated the framework does not know whether an emergency call should be placed using
+ * emergency or normal call routing. This means the underlying radio or IMS implementation is
+ * free to determine for itself how to route the call.
+ */
+ public static final int EMERGENCY_CALL_ROUTING_UNKNOWN = 0;
+ /**
+ * Indicates the radio or IMS implementation must handle the call through emergency routing.
+ */
+ public static final int EMERGENCY_CALL_ROUTING_EMERGENCY = 1;
+ /**
+ * Indicates the radio or IMS implementation must handle the call through normal call routing.
+ */
+ public static final int EMERGENCY_CALL_ROUTING_NORMAL = 2;
+
+ /**
+ * The routing to tell how to handle the call for the corresponding emergency number.
+ *
+ * @hide
+ */
+ @IntDef(flag = false, prefix = { "EMERGENCY_CALL_ROUTING_" }, value = {
+ EMERGENCY_CALL_ROUTING_UNKNOWN,
+ EMERGENCY_CALL_ROUTING_EMERGENCY,
+ EMERGENCY_CALL_ROUTING_NORMAL
+ })
+ @Retention(RetentionPolicy.SOURCE)
+ public @interface EmergencyCallRouting {}
+
+
private final String mNumber;
private final String mCountryIso;
private final String mMnc;
private final int mEmergencyServiceCategoryBitmask;
private final int mEmergencyNumberSourceBitmask;
+ private final int mEmergencyCallRouting;
/** @hide */
- public EmergencyNumber(@NonNull String number, @NonNull String countryIso,
- @NonNull String mnc, int emergencyServiceCategories,
- int emergencyNumberSources) {
+ public EmergencyNumber(@NonNull String number, @NonNull String countryIso, @NonNull String mnc,
+ @EmergencyServiceCategories int emergencyServiceCategories,
+ @EmergencyNumberSources int emergencyNumberSources,
+ @EmergencyCallRouting int emergencyCallRouting) {
this.mNumber = number;
this.mCountryIso = countryIso;
this.mMnc = mnc;
this.mEmergencyServiceCategoryBitmask = emergencyServiceCategories;
this.mEmergencyNumberSourceBitmask = emergencyNumberSources;
+ this.mEmergencyCallRouting = emergencyCallRouting;
}
/** @hide */
@@ -222,8 +255,33 @@
mMnc = source.readString();
mEmergencyServiceCategoryBitmask = source.readInt();
mEmergencyNumberSourceBitmask = source.readInt();
+ mEmergencyCallRouting = source.readInt();
}
+ @Override
+ /** @hide */
+ public void writeToParcel(Parcel dest, int flags) {
+ dest.writeString(mNumber);
+ dest.writeString(mCountryIso);
+ dest.writeString(mMnc);
+ dest.writeInt(mEmergencyServiceCategoryBitmask);
+ dest.writeInt(mEmergencyNumberSourceBitmask);
+ dest.writeInt(mEmergencyCallRouting);
+ }
+
+ public static final Parcelable.Creator<EmergencyNumber> CREATOR =
+ new Parcelable.Creator<EmergencyNumber>() {
+ @Override
+ public EmergencyNumber createFromParcel(Parcel in) {
+ return new EmergencyNumber(in);
+ }
+
+ @Override
+ public EmergencyNumber[] newArray(int size) {
+ return new EmergencyNumber[size];
+ }
+ };
+
/**
* Get the dialing number of the emergency number.
*
@@ -352,14 +410,17 @@
return (mEmergencyNumberSourceBitmask & sources) == sources;
}
- @Override
- /** @hide */
- public void writeToParcel(Parcel dest, int flags) {
- dest.writeString(mNumber);
- dest.writeString(mCountryIso);
- dest.writeString(mMnc);
- dest.writeInt(mEmergencyServiceCategoryBitmask);
- dest.writeInt(mEmergencyNumberSourceBitmask);
+ /**
+ * Returns the emergency call routing information.
+ *
+ * <p>Some regions require some emergency numbers which are not routed using typical emergency
+ * call processing, but are instead placed as regular phone calls. The emergency call routing
+ * field provides information about how an emergency call will be routed when it is placed.
+ *
+ * @return the emergency call routing requirement
+ */
+ public @EmergencyCallRouting int getEmergencyCallRouting() {
+ return mEmergencyCallRouting;
}
@Override
@@ -373,7 +434,8 @@
return "EmergencyNumber:" + "Number-" + mNumber + "|CountryIso-" + mCountryIso
+ "|Mnc-" + mMnc
+ "|ServiceCategories-" + Integer.toBinaryString(mEmergencyServiceCategoryBitmask)
- + "|Sources-" + Integer.toBinaryString(mEmergencyNumberSourceBitmask);
+ + "|Sources-" + Integer.toBinaryString(mEmergencyNumberSourceBitmask)
+ + "|Routing-" + Integer.toBinaryString(mEmergencyCallRouting);
}
@Override
@@ -381,7 +443,19 @@
if (!EmergencyNumber.class.isInstance(o)) {
return false;
}
- return (o == this || toString().equals(o.toString()));
+ EmergencyNumber other = (EmergencyNumber) o;
+ return mNumber.equals(other.mNumber)
+ && mCountryIso.equals(other.mCountryIso)
+ && mMnc.equals(other.mMnc)
+ && mEmergencyServiceCategoryBitmask == other.mEmergencyServiceCategoryBitmask
+ && mEmergencyNumberSourceBitmask == other.mEmergencyNumberSourceBitmask
+ && mEmergencyCallRouting == other.mEmergencyCallRouting;
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(mNumber, mCountryIso, mMnc, mEmergencyServiceCategoryBitmask,
+ mEmergencyNumberSourceBitmask, mEmergencyCallRouting);
}
/**
@@ -462,12 +536,12 @@
continue;
}
for (int j = i + 1; j < emergencyNumberList.size(); j++) {
- if (isSameEmergencyNumber(
+ if (areSameEmergencyNumbers(
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.set(i, mergeSameEmergencyNumbers(
emergencyNumberList.get(i), emergencyNumberList.get(j)));
// Mark the emergency number has been merged
mergedEmergencyNumber.add(emergencyNumberList.get(j));
@@ -486,8 +560,8 @@
* 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.
+ * 'categories', and 'routing' 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
@@ -495,8 +569,8 @@
*
* @hide
*/
- public static boolean isSameEmergencyNumber(@NonNull EmergencyNumber first,
- @NonNull EmergencyNumber second) {
+ public static boolean areSameEmergencyNumbers(@NonNull EmergencyNumber first,
+ @NonNull EmergencyNumber second) {
if (!first.getNumber().equals(second.getNumber())) {
return false;
}
@@ -510,11 +584,15 @@
!= second.getEmergencyServiceCategoryBitmask()) {
return false;
}
+ if (first.getEmergencyCallRouting() != second.getEmergencyCallRouting()) {
+ return false;
+ }
return true;
}
/**
- * Get a merged EmergencyNumber for two numbers if they are the same.
+ * Get a merged EmergencyNumber from two same emergency numbers. Two emergency numbers are
+ * the same if {@link #areSameEmergencyNumbers} returns {@code true}.
*
* @param first first EmergencyNumber to compare
* @param second second EmergencyNumber to compare
@@ -522,27 +600,15 @@
*
* @hide
*/
- public static EmergencyNumber mergeNumbers(@NonNull EmergencyNumber first,
- @NonNull EmergencyNumber second) {
- if (isSameEmergencyNumber(first, second)) {
+ public static EmergencyNumber mergeSameEmergencyNumbers(@NonNull EmergencyNumber first,
+ @NonNull EmergencyNumber second) {
+ if (areSameEmergencyNumbers(first, second)) {
return new EmergencyNumber(first.getNumber(), first.getCountryIso(), first.getMnc(),
first.getEmergencyServiceCategoryBitmask(),
first.getEmergencyNumberSourceBitmask()
- | second.getEmergencyNumberSourceBitmask());
+ | second.getEmergencyNumberSourceBitmask(),
+ first.getEmergencyCallRouting());
}
return null;
}
-
- public static final Parcelable.Creator<EmergencyNumber> CREATOR =
- new Parcelable.Creator<EmergencyNumber>() {
- @Override
- public EmergencyNumber createFromParcel(Parcel in) {
- return new EmergencyNumber(in);
- }
-
- @Override
- public EmergencyNumber[] newArray(int size) {
- return new EmergencyNumber[size];
- }
- };
}
diff --git a/telephony/java/android/telephony/euicc/EuiccManager.java b/telephony/java/android/telephony/euicc/EuiccManager.java
index 9164402..95dfffd 100644
--- a/telephony/java/android/telephony/euicc/EuiccManager.java
+++ b/telephony/java/android/telephony/euicc/EuiccManager.java
@@ -30,6 +30,7 @@
import android.os.Bundle;
import android.os.RemoteException;
import android.os.ServiceManager;
+import android.telephony.TelephonyManager;
import com.android.internal.telephony.euicc.IEuiccController;
@@ -40,7 +41,11 @@
* EuiccManager is the application interface to eUICCs, or eSIMs/embedded SIMs.
*
* <p>You do not instantiate this class directly; instead, you retrieve an instance through
- * {@link Context#getSystemService(String)} and {@link Context#EUICC_SERVICE}.
+ * {@link Context#getSystemService(String)} and {@link Context#EUICC_SERVICE}. This instance will be
+ * created using the default eUICC.
+ *
+ * <p>On a device with multiple eUICCs, you may want to create multiple EuiccManagers. To do this
+ * you can call {@link #createForCardId}.
*
* <p>See {@link #isEnabled} before attempting to use these APIs.
*/
@@ -248,10 +253,29 @@
public static final int EUICC_OTA_STATUS_UNAVAILABLE = 5;
private final Context mContext;
+ private final int mCardId;
/** @hide */
public EuiccManager(Context context) {
mContext = context;
+ TelephonyManager tm = (TelephonyManager)
+ context.getSystemService(Context.TELEPHONY_SERVICE);
+ mCardId = tm.getCardIdForDefaultEuicc();
+ }
+
+ /** @hide */
+ private EuiccManager(Context context, int cardId) {
+ mContext = context;
+ mCardId = cardId;
+ }
+
+ /**
+ * Create a new EuiccManager object pinned to the given card ID.
+ *
+ * @return an EuiccManager that uses the given card ID for all calls.
+ */
+ public EuiccManager createForCardId(int cardId) {
+ return new EuiccManager(mContext, cardId);
}
/**
@@ -274,7 +298,8 @@
* Returns the EID identifying the eUICC hardware.
*
* <p>Requires that the calling app has carrier privileges on the active subscription on the
- * eUICC.
+ * current eUICC. A calling app with carrier privileges for one eUICC may not necessarily have
+ * access to the EID of another eUICC.
*
* @return the EID. May be null if {@link #isEnabled()} is false or the eUICC is not ready.
*/
@@ -284,7 +309,7 @@
return null;
}
try {
- return getIEuiccController().getEid();
+ return getIEuiccController().getEid(mCardId);
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
@@ -307,7 +332,7 @@
return EUICC_OTA_STATUS_UNAVAILABLE;
}
try {
- return getIEuiccController().getOtaStatus();
+ return getIEuiccController().getOtaStatus(mCardId);
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
@@ -317,10 +342,10 @@
* Attempt to download the given {@link DownloadableSubscription}.
*
* <p>Requires the {@code android.Manifest.permission#WRITE_EMBEDDED_SUBSCRIPTIONS} permission,
- * or the calling app must be authorized to manage both the currently-active subscription and
- * the subscription to be downloaded according to the subscription metadata. Without the former,
- * an {@link #EMBEDDED_SUBSCRIPTION_RESULT_RESOLVABLE_ERROR} will be returned in the callback
- * intent to prompt the user to accept the download.
+ * or the calling app must be authorized to manage both the currently-active subscription on the
+ * current eUICC and the subscription to be downloaded according to the subscription metadata.
+ * Without the former, an {@link #EMBEDDED_SUBSCRIPTION_RESULT_RESOLVABLE_ERROR} will be
+ * returned in the callback intent to prompt the user to accept the download.
*
* @param subscription the subscription to download.
* @param switchAfterDownload if true, the profile will be activated upon successful download.
@@ -334,7 +359,7 @@
return;
}
try {
- getIEuiccController().downloadSubscription(subscription, switchAfterDownload,
+ getIEuiccController().downloadSubscription(mCardId, subscription, switchAfterDownload,
mContext.getOpPackageName(), null /* resolvedBundle */, callbackIntent);
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
@@ -401,7 +426,7 @@
return;
}
try {
- getIEuiccController().continueOperation(resolutionIntent, resolutionExtras);
+ getIEuiccController().continueOperation(mCardId, resolutionIntent, resolutionExtras);
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
@@ -433,8 +458,8 @@
return;
}
try {
- getIEuiccController().getDownloadableSubscriptionMetadata(
- subscription, mContext.getOpPackageName(), callbackIntent);
+ getIEuiccController().getDownloadableSubscriptionMetadata(mCardId, subscription,
+ mContext.getOpPackageName(), callbackIntent);
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
@@ -463,7 +488,7 @@
return;
}
try {
- getIEuiccController().getDefaultDownloadableSubscriptionList(
+ getIEuiccController().getDefaultDownloadableSubscriptionList(mCardId,
mContext.getOpPackageName(), callbackIntent);
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
@@ -482,7 +507,7 @@
return null;
}
try {
- return getIEuiccController().getEuiccInfo();
+ return getIEuiccController().getEuiccInfo(mCardId);
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
@@ -508,7 +533,7 @@
return;
}
try {
- getIEuiccController().deleteSubscription(
+ getIEuiccController().deleteSubscription(mCardId,
subscriptionId, mContext.getOpPackageName(), callbackIntent);
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
@@ -536,7 +561,7 @@
return;
}
try {
- getIEuiccController().switchToSubscription(
+ getIEuiccController().switchToSubscription(mCardId,
subscriptionId, mContext.getOpPackageName(), callbackIntent);
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
@@ -562,7 +587,7 @@
return;
}
try {
- getIEuiccController().updateSubscriptionNickname(
+ getIEuiccController().updateSubscriptionNickname(mCardId,
subscriptionId, nickname, mContext.getOpPackageName(), callbackIntent);
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
@@ -586,7 +611,7 @@
return;
}
try {
- getIEuiccController().eraseSubscriptions(callbackIntent);
+ getIEuiccController().eraseSubscriptions(mCardId, callbackIntent);
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
@@ -616,7 +641,7 @@
return;
}
try {
- getIEuiccController().retainSubscriptionsForFactoryReset(callbackIntent);
+ getIEuiccController().retainSubscriptionsForFactoryReset(mCardId, callbackIntent);
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
diff --git a/telephony/java/android/telephony/ims/ImsCallProfile.java b/telephony/java/android/telephony/ims/ImsCallProfile.java
index cb6fcd7..9c8d078 100644
--- a/telephony/java/android/telephony/ims/ImsCallProfile.java
+++ b/telephony/java/android/telephony/ims/ImsCallProfile.java
@@ -24,9 +24,11 @@
import android.os.Parcelable;
import android.telecom.VideoProfile;
import android.telephony.emergency.EmergencyNumber;
+import android.telephony.emergency.EmergencyNumber.EmergencyCallRouting;
import android.telephony.emergency.EmergencyNumber.EmergencyServiceCategories;
import android.util.Log;
+import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.telephony.PhoneConstants;
import java.lang.annotation.Retention;
@@ -321,6 +323,20 @@
EmergencyNumber.EMERGENCY_SERVICE_CATEGORY_UNSPECIFIED;
/**
+ * The emergency call routing, only valid if {@link #getServiceType} returns
+ * {@link #SERVICE_TYPE_EMERGENCY}
+ *
+ * If valid, the value is any of the following constants:
+ * <ol>
+ * <li>{@link EmergencyNumber#EMERGENCY_CALL_ROUTING_UNKNOWN} </li>
+ * <li>{@link EmergencyNumber#EMERGENCY_CALL_ROUTING_NORMAL} </li>
+ * <li>{@link EmergencyNumber#EMERGENCY_CALL_ROUTING_EMERGENCY} </li>
+ * </ol>
+ */
+ private @EmergencyCallRouting int mEmergencyCallRouting =
+ EmergencyNumber.EMERGENCY_CALL_ROUTING_UNKNOWN;
+
+ /**
* Extras associated with this {@link ImsCallProfile}.
* <p>
* Valid data types include:
@@ -503,10 +519,12 @@
@Override
public String toString() {
- return "{ serviceType=" + mServiceType +
- ", callType=" + mCallType +
- ", restrictCause=" + mRestrictCause +
- ", mediaProfile=" + mMediaProfile.toString() + " }";
+ return "{ serviceType=" + mServiceType
+ + ", callType=" + mCallType
+ + ", restrictCause=" + mRestrictCause
+ + ", mediaProfile=" + mMediaProfile.toString()
+ + ", emergencyServiceCategories=" + mEmergencyCallRouting
+ + ", emergencyCallRouting=" + mEmergencyCallRouting + " }";
}
@Override
@@ -522,6 +540,7 @@
out.writeBundle(filteredExtras);
out.writeParcelable(mMediaProfile, 0);
out.writeInt(mEmergencyServiceCategories);
+ out.writeInt(mEmergencyCallRouting);
}
private void readFromParcel(Parcel in) {
@@ -530,6 +549,7 @@
mCallExtras = in.readBundle();
mMediaProfile = in.readParcelable(ImsStreamMediaProfile.class.getClassLoader());
mEmergencyServiceCategories = in.readInt();
+ mEmergencyCallRouting = in.readInt();
}
public static final Creator<ImsCallProfile> CREATOR = new Creator<ImsCallProfile>() {
@@ -740,6 +760,21 @@
}
/**
+ * Set the emergency service categories and emergency call routing. The set value is valid
+ * only if {@link #getServiceType} returns {@link #SERVICE_TYPE_EMERGENCY}
+ *
+ * Reference: 3gpp 23.167, Section 6 - Functional description;
+ * 3gpp 22.101, Section 10 - Emergency Calls.
+ *
+ * @hide
+ */
+ public void setEmergencyCallInfo(EmergencyNumber num) {
+ setEmergencyServiceCategories(num.getEmergencyServiceCategoryBitmask());
+ setEmergencyCallRouting(num.getEmergencyCallRouting());
+ }
+
+
+ /**
* Set the emergency service categories. The set value is valid only if
* {@link #getServiceType} returns {@link #SERVICE_TYPE_EMERGENCY}
*
@@ -758,12 +793,29 @@
* Reference: 3gpp 23.167, Section 6 - Functional description;
* 3gpp 22.101, Section 10 - Emergency Calls.
*/
+ @VisibleForTesting
public void setEmergencyServiceCategories(
@EmergencyServiceCategories int emergencyServiceCategories) {
mEmergencyServiceCategories = emergencyServiceCategories;
}
/**
+ * Set the emergency call routing, only valid if {@link #getServiceType} returns
+ * {@link #SERVICE_TYPE_EMERGENCY}
+ *
+ * If valid, the value is any of the following constants:
+ * <ol>
+ * <li>{@link EmergencyNumber#EMERGENCY_CALL_ROUTING_UNKNOWN} </li>
+ * <li>{@link EmergencyNumber#EMERGENCY_CALL_ROUTING_NORMAL} </li>
+ * <li>{@link EmergencyNumber#EMERGENCY_CALL_ROUTING_EMERGENCY} </li>
+ * </ol>
+ */
+ @VisibleForTesting
+ public void setEmergencyCallRouting(@EmergencyCallRouting int emergencyCallRouting) {
+ mEmergencyCallRouting = emergencyCallRouting;
+ }
+
+ /**
* Get the emergency service categories, only valid if {@link #getServiceType} returns
* {@link #SERVICE_TYPE_EMERGENCY}
*
@@ -787,4 +839,19 @@
public @EmergencyServiceCategories int getEmergencyServiceCategories() {
return mEmergencyServiceCategories;
}
+
+ /**
+ * Get the emergency call routing, only valid if {@link #getServiceType} returns
+ * {@link #SERVICE_TYPE_EMERGENCY}
+ *
+ * If valid, the value is any of the following constants:
+ * <ol>
+ * <li>{@link EmergencyNumber#EMERGENCY_CALL_ROUTING_UNKNOWN} </li>
+ * <li>{@link EmergencyNumber#EMERGENCY_CALL_ROUTING_NORMAL} </li>
+ * <li>{@link EmergencyNumber#EMERGENCY_CALL_ROUTING_EMERGENCY} </li>
+ * </ol>
+ */
+ public @EmergencyCallRouting int getEmergencyCallRouting() {
+ return mEmergencyCallRouting;
+ }
}
diff --git a/telephony/java/android/telephony/ims/ImsMmTelManager.java b/telephony/java/android/telephony/ims/ImsMmTelManager.java
index e2350fe..9414abd 100644
--- a/telephony/java/android/telephony/ims/ImsMmTelManager.java
+++ b/telephony/java/android/telephony/ims/ImsMmTelManager.java
@@ -92,7 +92,7 @@
public static final int WIFI_MODE_WIFI_PREFERRED = 2;
/**
- * Callback class for receiving Registration callback events.
+ * Callback class for receiving IMS network Registration callback events.
* @see #registerImsRegistrationCallback(Executor, RegistrationCallback) (RegistrationCallback)
* @see #unregisterImsRegistrationCallback(RegistrationCallback)
*/
@@ -241,7 +241,8 @@
}
/**
- * Receives IMS capability status updates from the ImsService.
+ * Receives IMS capability status updates from the ImsService. This information is also
+ * available via the {@link #isAvailable(int, int)} method below.
*
* @see #registerMmTelCapabilityCallback(Executor, CapabilityCallback) (CapabilityCallback)
* @see #unregisterMmTelCapabilityCallback(CapabilityCallback)
@@ -290,6 +291,8 @@
* If unavailable, the feature is not able to support the unavailable capability at this
* time.
*
+ * This information can also be queried using the {@link #isAvailable(int, int)} API.
+ *
* @param capabilities The new availability of the capabilities.
*/
public void onCapabilitiesStatusChanged(
@@ -304,7 +307,7 @@
/**@hide*/
// Only exposed as public method for compatibility with deprecated ImsManager APIs.
// TODO: clean up dependencies and change back to private visibility.
- public void setExecutor(Executor executor) {
+ public final void setExecutor(Executor executor) {
mBinder.setExecutor(executor);
}
}
@@ -342,8 +345,7 @@
* Registers a {@link RegistrationCallback} with the system, which will provide registration
* updates for the subscription specified in {@link #createForSubscriptionId(Context, int)}. Use
* {@link SubscriptionManager.OnSubscriptionsChangedListener} to listen to Subscription changed
- * events and call {@link #unregisterImsRegistrationCallback(RegistrationCallback)} to clean up
- * after a subscription is removed.
+ * events and call {@link #unregisterImsRegistrationCallback(RegistrationCallback)} to clean up.
*
* When the callback is registered, it will initiate the callback c to be called with the
* current registration state.
@@ -351,6 +353,12 @@
* @param executor The executor the callback events should be run on.
* @param c The {@link RegistrationCallback} to be added.
* @see #unregisterImsRegistrationCallback(RegistrationCallback)
+ * @throws IllegalArgumentException if the subscription associated with this callback is not
+ * active (SIM is not inserted, ESIM inactive) or invalid, or a null {@link Executor} or
+ * {@link CapabilityCallback} callback.
+ * @throws IllegalStateException if the subscription associated with this callback is valid, but
+ * the {@link ImsService} associated with the subscription is not available. This can happen if
+ * the service crashed, for example.
*/
@RequiresPermission(Manifest.permission.READ_PRIVILEGED_PHONE_STATE)
public void registerImsRegistrationCallback(@CallbackExecutor Executor executor,
@@ -370,11 +378,17 @@
}
/**
- * Removes an existing {@link RegistrationCallback}. Ensure to call this method when cleaning
- * up to avoid memory leaks or when the subscription is removed.
+ * Removes an existing {@link RegistrationCallback}.
+ *
+ * When the subscription associated with this callback is removed (SIM removed, ESIM swap,
+ * etc...), this callback will automatically be removed. If this method is called for an
+ * inactive subscription, it will result in a no-op.
+ *
* @param c The {@link RegistrationCallback} to be removed.
* @see SubscriptionManager.OnSubscriptionsChangedListener
* @see #registerImsRegistrationCallback(Executor, RegistrationCallback)
+ * @throws IllegalArgumentException if the subscription ID associated with this callback is
+ * invalid.
*/
@RequiresPermission(Manifest.permission.READ_PRIVILEGED_PHONE_STATE)
public void unregisterImsRegistrationCallback(@NonNull RegistrationCallback c) {
@@ -389,12 +403,14 @@
}
/**
- * Registers a {@link CapabilityCallback} with the system, which will provide MmTel capability
- * updates for the subscription specified in {@link #createForSubscriptionId(Context, int)}.
+ * Registers a {@link CapabilityCallback} with the system, which will provide MmTel service
+ * availability updates for the subscription specified in
+ * {@link #createForSubscriptionId(Context, int)}. The method {@link #isAvailable(int, int)}
+ * can also be used to query this information at any time.
+ *
* Use {@link SubscriptionManager.OnSubscriptionsChangedListener} to listen to
* subscription changed events and call
- * {@link #unregisterImsRegistrationCallback(RegistrationCallback)} to clean up after a
- * subscription is removed.
+ * {@link #unregisterImsRegistrationCallback(RegistrationCallback)} to clean up.
*
* When the callback is registered, it will initiate the callback c to be called with the
* current capabilities.
@@ -402,9 +418,15 @@
* @param executor The executor the callback events should be run on.
* @param c The MmTel {@link CapabilityCallback} to be registered.
* @see #unregisterMmTelCapabilityCallback(CapabilityCallback)
+ * @throws IllegalArgumentException if the subscription associated with this callback is not
+ * active (SIM is not inserted, ESIM inactive) or invalid, or a null {@link Executor} or
+ * {@link CapabilityCallback} callback.
+ * @throws IllegalStateException if the subscription associated with this callback is valid, but
+ * the {@link ImsService} associated with the subscription is not available. This can happen if
+ * the service crashed, for example.
*/
@RequiresPermission(Manifest.permission.READ_PRIVILEGED_PHONE_STATE)
- public void registerMmTelCapabilityCallback(@CallbackExecutor Executor executor,
+ public void registerMmTelCapabilityCallback(@NonNull @CallbackExecutor Executor executor,
@NonNull CapabilityCallback c) {
if (c == null) {
throw new IllegalArgumentException("Must include a non-null RegistrationCallback.");
@@ -421,10 +443,15 @@
}
/**
- * Removes an existing MmTel {@link CapabilityCallback}. Be sure to call this when cleaning
- * up to avoid memory leaks.
+ * Removes an existing MmTel {@link CapabilityCallback}.
+ *
+ * When the subscription associated with this callback is removed (SIM removed, ESIM swap,
+ * etc...), this callback will automatically be removed. If this method is called for an
+ * inactive subscription, it will result in a no-op.
* @param c The MmTel {@link CapabilityCallback} to be removed.
* @see #registerMmTelCapabilityCallback(Executor, CapabilityCallback)
+ * @throws IllegalArgumentException if the subscription ID associated with this callback is
+ * invalid.
*/
@RequiresPermission(Manifest.permission.READ_PRIVILEGED_PHONE_STATE)
public void unregisterMmTelCapabilityCallback(@NonNull CapabilityCallback c) {
diff --git a/telephony/java/android/telephony/ims/ProvisioningManager.java b/telephony/java/android/telephony/ims/ProvisioningManager.java
index 916e282..d37198a 100644
--- a/telephony/java/android/telephony/ims/ProvisioningManager.java
+++ b/telephony/java/android/telephony/ims/ProvisioningManager.java
@@ -133,33 +133,40 @@
}
/**
- * Register a new {@link Callback} to listen to changes to changes in
- * IMS provisioning. Use {@link SubscriptionManager.OnSubscriptionsChangedListener} to listen to
- * Subscription changed events and call
- * {@link #unregisterProvisioningChangedCallback(Callback)} to clean up after a
- * subscription is removed.
+ * Register a new {@link Callback} to listen to changes to changes in IMS provisioning.
+ *
+ * When the subscription associated with this callback is removed (SIM removed, ESIM swap,
+ * etc...), this callback will automatically be removed.
* @param executor The {@link Executor} to call the callback methods on
* @param callback The provisioning callbackto be registered.
* @see #unregisterProvisioningChangedCallback(Callback)
* @see SubscriptionManager.OnSubscriptionsChangedListener
+ * @throws IllegalArgumentException if the subscription associated with this callback is not
+ * active (SIM is not inserted, ESIM inactive) or the subscription is invalid.
+ * @throws IllegalStateException if the subscription associated with this callback is valid, but
+ * the {@link ImsService} associated with the subscription is not available. This can happen if
+ * the service crashed, for example.
*/
@RequiresPermission(Manifest.permission.READ_PRIVILEGED_PHONE_STATE)
public void registerProvisioningChangedCallback(@CallbackExecutor Executor executor,
@NonNull Callback callback) {
callback.setExecutor(executor);
try {
- getITelephony().registerImsProvisioningChangedCallback(mSubId,
- callback.getBinder());
+ getITelephony().registerImsProvisioningChangedCallback(mSubId, callback.getBinder());
} catch (RemoteException e) {
throw e.rethrowAsRuntimeException();
}
}
/**
- * Unregister an existing {@link Callback}. Ensure to call this method when cleaning
- * up to avoid memory leaks or when the subscription is removed.
+ * Unregister an existing {@link Callback}. When the subscription associated with this
+ * callback is removed (SIM removed, ESIM swap, etc...), this callback will automatically be
+ * removed. If this method is called for an inactive subscription, it will result in a no-op.
* @param callback The existing {@link Callback} to be removed.
* @see #registerProvisioningChangedCallback(Executor, Callback)
+ *
+ * @throws IllegalArgumentException if the subscription associated with this callback is
+ * invalid.
*/
@RequiresPermission(Manifest.permission.READ_PRIVILEGED_PHONE_STATE)
public void unregisterProvisioningChangedCallback(@NonNull Callback callback) {
diff --git a/telephony/java/com/android/internal/telephony/euicc/IEuiccController.aidl b/telephony/java/com/android/internal/telephony/euicc/IEuiccController.aidl
index dd40d56..14a36c8 100644
--- a/telephony/java/com/android/internal/telephony/euicc/IEuiccController.aidl
+++ b/telephony/java/com/android/internal/telephony/euicc/IEuiccController.aidl
@@ -24,22 +24,25 @@
/** @hide */
interface IEuiccController {
- oneway void continueOperation(in Intent resolutionIntent, in Bundle resolutionExtras);
- oneway void getDownloadableSubscriptionMetadata(in DownloadableSubscription subscription,
+ oneway void continueOperation(int cardId, in Intent resolutionIntent,
+ in Bundle resolutionExtras);
+ oneway void getDownloadableSubscriptionMetadata(int cardId,
+ in DownloadableSubscription subscription,
String callingPackage, in PendingIntent callbackIntent);
- oneway void getDefaultDownloadableSubscriptionList(
+ oneway void getDefaultDownloadableSubscriptionList(int cardId,
String callingPackage, in PendingIntent callbackIntent);
- String getEid();
- int getOtaStatus();
- oneway void downloadSubscription(in DownloadableSubscription subscription,
- boolean switchAfterDownload, String callingPackage, in Bundle resolvedBundle, in PendingIntent callbackIntent);
- EuiccInfo getEuiccInfo();
- oneway void deleteSubscription(int subscriptionId, String callingPackage,
+ String getEid(int cardId);
+ int getOtaStatus(int cardId);
+ oneway void downloadSubscription(int cardId, in DownloadableSubscription subscription,
+ boolean switchAfterDownload, String callingPackage, in Bundle resolvedBundle,
in PendingIntent callbackIntent);
- oneway void switchToSubscription(int subscriptionId, String callingPackage,
+ EuiccInfo getEuiccInfo(int cardId);
+ oneway void deleteSubscription(int cardId, int subscriptionId, String callingPackage,
in PendingIntent callbackIntent);
- oneway void updateSubscriptionNickname(int subscriptionId, String nickname,
+ oneway void switchToSubscription(int cardId, int subscriptionId, String callingPackage,
+ in PendingIntent callbackIntent);
+ oneway void updateSubscriptionNickname(int cardId, int subscriptionId, String nickname,
String callingPackage, in PendingIntent callbackIntent);
- oneway void eraseSubscriptions(in PendingIntent callbackIntent);
- oneway void retainSubscriptionsForFactoryReset(in PendingIntent callbackIntent);
-}
\ No newline at end of file
+ oneway void eraseSubscriptions(int cardId, in PendingIntent callbackIntent);
+ oneway void retainSubscriptionsForFactoryReset(int cardId, in PendingIntent callbackIntent);
+}
diff --git a/test-legacy/Android.bp b/test-legacy/Android.bp
index 833c714..a69f422 100644
--- a/test-legacy/Android.bp
+++ b/test-legacy/Android.bp
@@ -25,7 +25,7 @@
static_libs: [
"android.test.base-minus-junit",
"android.test.runner-minus-junit",
- "android.test.mock.impl",
+ "android.test.mock_static",
],
no_framework_libs: true,
diff --git a/test-mock/Android.bp b/test-mock/Android.bp
index e1d6e01..43b765d 100644
--- a/test-mock/Android.bp
+++ b/test-mock/Android.bp
@@ -30,3 +30,19 @@
srcs_lib_whitelist_pkgs: ["android"],
compile_dex: true,
}
+
+// Build the android.test.mock_static library
+// ==========================================
+// This is only intended for inclusion in the legacy-android-test.
+// Must not be used elewhere.
+java_library_static {
+ name: "android.test.mock_static",
+
+ java_version: "1.8",
+ srcs: ["src/**/*.java"],
+
+ no_framework_libs: true,
+ libs: [
+ "framework",
+ ],
+}
diff --git a/tests/net/java/android/net/shared/LinkPropertiesParcelableUtilTest.java b/tests/net/java/android/net/shared/LinkPropertiesParcelableUtilTest.java
new file mode 100644
index 0000000..4cabfc9
--- /dev/null
+++ b/tests/net/java/android/net/shared/LinkPropertiesParcelableUtilTest.java
@@ -0,0 +1,193 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.net.shared;
+
+import static android.net.shared.LinkPropertiesParcelableUtil.fromStableParcelable;
+import static android.net.shared.LinkPropertiesParcelableUtil.toStableParcelable;
+
+import static org.junit.Assert.assertEquals;
+
+import android.net.InetAddresses;
+import android.net.IpPrefix;
+import android.net.LinkAddress;
+import android.net.LinkProperties;
+import android.net.ProxyInfo;
+import android.net.RouteInfo;
+import android.net.Uri;
+import android.support.test.filters.SmallTest;
+import android.support.test.runner.AndroidJUnit4;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import java.lang.reflect.Modifier;
+import java.util.Arrays;
+import java.util.Collections;
+
+/**
+ * Tests for {@link LinkPropertiesParcelableUtil}
+ */
+@RunWith(AndroidJUnit4.class)
+@SmallTest
+public class LinkPropertiesParcelableUtilTest {
+ private LinkProperties mLinkProperties;
+
+ private static final String TEST_LINKPROPS_IFACE = "TEST_IFACE";
+ private static final String TEST_STACKED_LINK_1_IFACE = "TEST_STACKED_IFACE_1";
+ private static final String TEST_STACKED_LINK_2_IFACE = "TEST_STACKED_IFACE_2";
+
+ @Before
+ public void setUp() {
+ mLinkProperties = makeLinkProperties(TEST_LINKPROPS_IFACE);
+ mLinkProperties.addStackedLink(makeLinkProperties(TEST_STACKED_LINK_1_IFACE));
+ mLinkProperties.addStackedLink(makeLinkProperties(TEST_STACKED_LINK_2_IFACE));
+ }
+
+ private static LinkProperties makeLinkProperties(String iface) {
+ final LinkProperties lp = new LinkProperties();
+ lp.setInterfaceName(iface);
+ lp.setLinkAddresses(Arrays.asList(
+ new LinkAddress(InetAddresses.parseNumericAddress("192.168.0.42"), 16),
+ new LinkAddress(InetAddresses.parseNumericAddress("2001:db8::7"), 42)));
+ lp.setDnsServers(Arrays.asList(
+ InetAddresses.parseNumericAddress("2001:db8::42"),
+ InetAddresses.parseNumericAddress("192.168.1.1")
+ ));
+ lp.setValidatedPrivateDnsServers(Arrays.asList(
+ InetAddresses.parseNumericAddress("2001:db8::43"),
+ InetAddresses.parseNumericAddress("192.168.42.43")
+ ));
+ lp.setPcscfServers(Arrays.asList(
+ InetAddresses.parseNumericAddress("2001:db8::47"),
+ InetAddresses.parseNumericAddress("192.168.42.47")
+ ));
+ lp.setUsePrivateDns(true);
+ lp.setPrivateDnsServerName("test.example.com");
+ lp.setDomains("test1.example.com,test2.example.com");
+ lp.addRoute(new RouteInfo(
+ new IpPrefix(InetAddresses.parseNumericAddress("2001:db8::44"), 45),
+ InetAddresses.parseNumericAddress("2001:db8::45"),
+ iface,
+ RouteInfo.RTN_UNICAST
+ ));
+ lp.addRoute(new RouteInfo(
+ new IpPrefix(InetAddresses.parseNumericAddress("192.168.44.45"), 16),
+ InetAddresses.parseNumericAddress("192.168.45.1"),
+ iface,
+ RouteInfo.RTN_THROW
+ ));
+ lp.setHttpProxy(new ProxyInfo("test3.example.com", 8000,
+ "excl1.example.com,excl2.example.com"));
+ lp.setMtu(5000);
+ lp.setTcpBufferSizes("1,2,3,4,5,6");
+ lp.setNat64Prefix(new IpPrefix(InetAddresses.parseNumericAddress("2001:db8::48"), 96));
+
+ // Verify that this test does not miss any new field added later.
+ // If any added field is not included in LinkProperties#equals, assertLinkPropertiesEquals
+ // must also be updated.
+ assertEquals(14, Arrays.stream(LinkProperties.class.getDeclaredFields())
+ .filter(f -> !Modifier.isStatic(f.getModifiers())).count());
+
+ return lp;
+ }
+
+ @Test
+ public void testParcelUnparcel() {
+ doParcelUnparcelTest();
+ }
+
+ @Test
+ public void testParcelUnparcel_NullInterface() {
+ mLinkProperties.setInterfaceName(null);
+ doParcelUnparcelTest();
+ }
+
+ @Test
+ public void testParcelUnparcel_NullPrivateDnsServer() {
+ mLinkProperties.setPrivateDnsServerName(null);
+ doParcelUnparcelTest();
+ }
+
+ @Test
+ public void testParcelUnparcel_NullDomains() {
+ mLinkProperties.setDomains(null);
+ doParcelUnparcelTest();
+ }
+
+ @Test
+ public void testParcelUnparcel_NullProxy() {
+ mLinkProperties.setHttpProxy(null);
+ doParcelUnparcelTest();
+ }
+
+ @Test
+ public void testParcelUnparcel_NullTcpBufferSizes() {
+ mLinkProperties.setTcpBufferSizes(null);
+ doParcelUnparcelTest();
+ }
+
+ @Test
+ public void testParcelUnparcel_EmptyLinkAddresses() {
+ mLinkProperties.setLinkAddresses(Collections.emptyList());
+ doParcelUnparcelTest();
+ }
+
+ @Test
+ public void testParcelUnparcel_EmptyDnses() {
+ mLinkProperties.setDnsServers(Collections.emptyList());
+ doParcelUnparcelTest();
+ }
+
+ @Test
+ public void testParcelUnparcel_EmptyValidatedPrivateDnses() {
+ mLinkProperties.setValidatedPrivateDnsServers(Collections.emptyList());
+ doParcelUnparcelTest();
+ }
+
+ @Test
+ public void testParcelUnparcel_EmptyRoutes() {
+ for (RouteInfo r : mLinkProperties.getAllRoutes()) {
+ mLinkProperties.removeRoute(r);
+ }
+ doParcelUnparcelTest();
+ }
+
+ @Test
+ public void testParcelUnparcel_PacFileProxyInfo() {
+ mLinkProperties.setHttpProxy(new ProxyInfo(Uri.parse("http://pacfile.example.com")));
+ doParcelUnparcelTest();
+ }
+
+ @Test
+ public void testParcelUnparcel_NullNat64Prefix() {
+ mLinkProperties.setNat64Prefix(null);
+ doParcelUnparcelTest();
+ }
+
+ private void doParcelUnparcelTest() {
+ final LinkProperties unparceled = fromStableParcelable(toStableParcelable(mLinkProperties));
+ assertLinkPropertiesEquals(mLinkProperties, unparceled);
+ }
+
+ private static void assertLinkPropertiesEquals(LinkProperties expected, LinkProperties actual) {
+ assertEquals(expected, actual);
+
+ // LinkProperties equals() does not include stacked links
+ assertEquals(expected.getStackedLinks(), actual.getStackedLinks());
+ }
+}