diff options
80 files changed, 2142 insertions, 408 deletions
diff --git a/Android.mk b/Android.mk index 02caa0ad3866..2571afbf477f 100644 --- a/Android.mk +++ b/Android.mk @@ -553,7 +553,6 @@ aidl_files := \ frameworks/base/telephony/java/android/telephony/mbms/FileInfo.aidl \ frameworks/base/telephony/java/android/telephony/mbms/FileServiceInfo.aidl \ frameworks/base/telephony/java/android/telephony/mbms/ServiceInfo.aidl \ - frameworks/base/telephony/java/android/telephony/mbms/StreamingService.aidl \ frameworks/base/telephony/java/android/telephony/mbms/StreamingServiceInfo.aidl \ frameworks/base/telephony/java/android/telephony/ServiceState.aidl \ frameworks/base/telephony/java/android/telephony/SubscriptionInfo.aidl \ diff --git a/api/current.txt b/api/current.txt index 0353a8bd112e..55dda042e19c 100644 --- a/api/current.txt +++ b/api/current.txt @@ -37531,6 +37531,7 @@ package android.telephony { field public static final java.lang.String KEY_CARRIER_SETTINGS_ENABLE_BOOL = "carrier_settings_enable_bool"; field public static final java.lang.String KEY_CARRIER_USE_IMS_FIRST_FOR_EMERGENCY_BOOL = "carrier_use_ims_first_for_emergency_bool"; field public static final java.lang.String KEY_CARRIER_VOLTE_AVAILABLE_BOOL = "carrier_volte_available_bool"; + field public static final java.lang.String KEY_CARRIER_VOLTE_PROVISIONED_BOOL = "carrier_volte_provisioned_bool"; field public static final java.lang.String KEY_CARRIER_VOLTE_PROVISIONING_REQUIRED_BOOL = "carrier_volte_provisioning_required_bool"; field public static final java.lang.String KEY_CARRIER_VOLTE_TTY_SUPPORTED_BOOL = "carrier_volte_tty_supported_bool"; field public static final java.lang.String KEY_CARRIER_VT_AVAILABLE_BOOL = "carrier_vt_available_bool"; diff --git a/api/system-current.txt b/api/system-current.txt index eb6b7b15c8c7..5e9c7e39bfda 100644 --- a/api/system-current.txt +++ b/api/system-current.txt @@ -40702,6 +40702,7 @@ package android.telephony { field public static final java.lang.String KEY_CARRIER_SETTINGS_ENABLE_BOOL = "carrier_settings_enable_bool"; field public static final java.lang.String KEY_CARRIER_USE_IMS_FIRST_FOR_EMERGENCY_BOOL = "carrier_use_ims_first_for_emergency_bool"; field public static final java.lang.String KEY_CARRIER_VOLTE_AVAILABLE_BOOL = "carrier_volte_available_bool"; + field public static final java.lang.String KEY_CARRIER_VOLTE_PROVISIONED_BOOL = "carrier_volte_provisioned_bool"; field public static final java.lang.String KEY_CARRIER_VOLTE_PROVISIONING_REQUIRED_BOOL = "carrier_volte_provisioning_required_bool"; field public static final java.lang.String KEY_CARRIER_VOLTE_TTY_SUPPORTED_BOOL = "carrier_volte_tty_supported_bool"; field public static final java.lang.String KEY_CARRIER_VT_AVAILABLE_BOOL = "carrier_vt_available_bool"; diff --git a/api/test-current.txt b/api/test-current.txt index 8946dafee8d9..5487a9770fd1 100644 --- a/api/test-current.txt +++ b/api/test-current.txt @@ -37630,6 +37630,7 @@ package android.telephony { field public static final java.lang.String KEY_CARRIER_SETTINGS_ENABLE_BOOL = "carrier_settings_enable_bool"; field public static final java.lang.String KEY_CARRIER_USE_IMS_FIRST_FOR_EMERGENCY_BOOL = "carrier_use_ims_first_for_emergency_bool"; field public static final java.lang.String KEY_CARRIER_VOLTE_AVAILABLE_BOOL = "carrier_volte_available_bool"; + field public static final java.lang.String KEY_CARRIER_VOLTE_PROVISIONED_BOOL = "carrier_volte_provisioned_bool"; field public static final java.lang.String KEY_CARRIER_VOLTE_PROVISIONING_REQUIRED_BOOL = "carrier_volte_provisioning_required_bool"; field public static final java.lang.String KEY_CARRIER_VOLTE_TTY_SUPPORTED_BOOL = "carrier_volte_tty_supported_bool"; field public static final java.lang.String KEY_CARRIER_VT_AVAILABLE_BOOL = "carrier_vt_available_bool"; diff --git a/core/java/android/bluetooth/BluetoothGatt.java b/core/java/android/bluetooth/BluetoothGatt.java index 3135b30ebcc8..b12ff72a50c6 100644 --- a/core/java/android/bluetooth/BluetoothGatt.java +++ b/core/java/android/bluetooth/BluetoothGatt.java @@ -16,7 +16,6 @@ package android.bluetooth; -import android.content.Context; import android.os.Handler; import android.os.ParcelUuid; import android.os.RemoteException; @@ -927,6 +926,31 @@ public final class BluetoothGatt implements BluetoothProfile { } /** + * Discovers a service by UUID. This is exposed only for passing PTS tests. + * It should never be used by real applications. The service is not searched + * for characteristics and descriptors, or returned in any callback. + * + * <p>Requires {@link android.Manifest.permission#BLUETOOTH} permission. + * + * @return true, if the remote service discovery has been started + * @hide + */ + public boolean discoverServiceByUuid(UUID uuid) { + if (DBG) Log.d(TAG, "discoverServiceByUuid() - device: " + mDevice.getAddress()); + if (mService == null || mClientIf == 0) return false; + + mServices.clear(); + + try { + mService.discoverServiceByUuid(mClientIf, mDevice.getAddress(), new ParcelUuid(uuid)); + } catch (RemoteException e) { + Log.e(TAG, "", e); + return false; + } + return true; + } + + /** * Returns a list of GATT services offered by the remote device. * * <p>This function requires that service discovery has been completed diff --git a/core/java/android/bluetooth/BluetoothInputDevice.java b/core/java/android/bluetooth/BluetoothInputDevice.java index 252e3d28a25e..fccdf14bb9cd 100644 --- a/core/java/android/bluetooth/BluetoothInputDevice.java +++ b/core/java/android/bluetooth/BluetoothInputDevice.java @@ -96,6 +96,12 @@ public final class BluetoothInputDevice implements BluetoothProfile { public static final String ACTION_VIRTUAL_UNPLUG_STATUS = "android.bluetooth.input.profile.action.VIRTUAL_UNPLUG_STATUS"; + /** + * @hide + */ + @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION) + public static final String ACTION_IDLE_TIME_CHANGED = + "android.bluetooth.input.profile.action.IDLE_TIME_CHANGED"; /** * Return codes for the connect and disconnect Bluez / Dbus calls. @@ -199,6 +205,11 @@ public final class BluetoothInputDevice implements BluetoothProfile { */ public static final String EXTRA_VIRTUAL_UNPLUG_STATUS = "android.bluetooth.BluetoothInputDevice.extra.VIRTUAL_UNPLUG_STATUS"; + /** + * @hide + */ + public static final String EXTRA_IDLE_TIME = "android.bluetooth.BluetoothInputDevice.extra.IDLE_TIME"; + private Context mContext; private ServiceListener mServiceListener; private BluetoothAdapter mAdapter; @@ -658,6 +669,56 @@ public final class BluetoothInputDevice implements BluetoothProfile { if (mService == null) Log.w(TAG, "Proxy not attached to service"); return false; } + + /** + * Send Get_Idle_Time command to the connected HID input device. + * + * <p>Requires {@link android.Manifest.permission#BLUETOOTH_ADMIN} permission. + * + * @param device Remote Bluetooth Device + * @return false on immediate error, + * true otherwise + * @hide + */ + public boolean getIdleTime(BluetoothDevice device) { + if (DBG) log("getIdletime(" + device + ")"); + if (mService != null && isEnabled() && isValidDevice(device)) { + try { + return mService.getIdleTime(device); + } catch (RemoteException e) { + Log.e(TAG, "Stack:" + Log.getStackTraceString(new Throwable())); + return false; + } + } + if (mService == null) Log.w(TAG, "Proxy not attached to service"); + return false; + } + + /** + * Send Set_Idle_Time command to the connected HID input device. + * + * <p>Requires {@link android.Manifest.permission#BLUETOOTH_ADMIN} permission. + * + * @param device Remote Bluetooth Device + * @param idleTime Idle time to be set on HID Device + * @return false on immediate error, + * true otherwise + * @hide + */ + public boolean setIdleTime(BluetoothDevice device, byte idleTime) { + if (DBG) log("setIdletime(" + device + "), idleTime=" + idleTime); + if (mService != null && isEnabled() && isValidDevice(device)) { + try { + return mService.setIdleTime(device, idleTime); + } catch (RemoteException e) { + Log.e(TAG, "Stack:" + Log.getStackTraceString(new Throwable())); + return false; + } + } + if (mService == null) Log.w(TAG, "Proxy not attached to service"); + return false; + } + private static void log(String msg) { Log.d(TAG, msg); } diff --git a/core/java/android/bluetooth/IBluetoothGatt.aidl b/core/java/android/bluetooth/IBluetoothGatt.aidl index 63bd94284645..4ff597655767 100644 --- a/core/java/android/bluetooth/IBluetoothGatt.aidl +++ b/core/java/android/bluetooth/IBluetoothGatt.aidl @@ -76,6 +76,7 @@ interface IBluetoothGatt { void clientReadPhy(in int clientIf, in String address); void refreshDevice(in int clientIf, in String address); void discoverServices(in int clientIf, in String address); + void discoverServiceByUuid(in int clientIf, in String address, in ParcelUuid uuid); void readCharacteristic(in int clientIf, in String address, in int handle, in int authReq); void readUsingCharacteristicUuid(in int clientIf, in String address, in ParcelUuid uuid, in int startHandle, in int endHandle, in int authReq); diff --git a/core/java/android/bluetooth/IBluetoothInputDevice.aidl b/core/java/android/bluetooth/IBluetoothInputDevice.aidl index 1ebb9ca6eb12..5bd3f7819323 100644 --- a/core/java/android/bluetooth/IBluetoothInputDevice.aidl +++ b/core/java/android/bluetooth/IBluetoothInputDevice.aidl @@ -56,4 +56,12 @@ interface IBluetoothInputDevice { * @hide */ boolean sendData(in BluetoothDevice device, String report); + /** + * @hide + */ + boolean getIdleTime(in BluetoothDevice device); + /** + * @hide + */ + boolean setIdleTime(in BluetoothDevice device, byte idleTime); } diff --git a/core/java/android/net/ConnectivityManager.java b/core/java/android/net/ConnectivityManager.java index efa195983f94..234bef7483aa 100644 --- a/core/java/android/net/ConnectivityManager.java +++ b/core/java/android/net/ConnectivityManager.java @@ -39,11 +39,11 @@ import android.os.Process; import android.os.RemoteException; import android.os.ResultReceiver; import android.os.ServiceManager; +import android.os.ServiceSpecificException; import android.provider.Settings; import android.telephony.SubscriptionManager; import android.util.ArrayMap; import android.util.Log; -import android.util.SparseArray; import android.util.SparseIntArray; import com.android.internal.telephony.ITelephony; @@ -2701,6 +2701,28 @@ public class ConnectivityManager { } } + /** + * Constant error codes used by ConnectivityService to communicate about failures and errors + * across a Binder boundary. + * @hide + */ + public interface Errors { + static int TOO_MANY_REQUESTS = 1; + } + + /** @hide */ + public static class TooManyRequestsException extends RuntimeException {} + + private static RuntimeException convertServiceException(ServiceSpecificException e) { + switch (e.errorCode) { + case Errors.TOO_MANY_REQUESTS: + return new TooManyRequestsException(); + default: + Log.w(TAG, "Unknown service error code " + e.errorCode); + return new RuntimeException(e); + } + } + private static final int BASE = Protocol.BASE_CONNECTIVITY_MANAGER; /** @hide */ public static final int CALLBACK_PRECHECK = BASE + 1; @@ -2892,6 +2914,8 @@ public class ConnectivityManager { } } catch (RemoteException e) { throw e.rethrowFromSystemServer(); + } catch (ServiceSpecificException e) { + throw convertServiceException(e); } return request; } @@ -3177,6 +3201,8 @@ public class ConnectivityManager { mService.pendingRequestForNetwork(request.networkCapabilities, operation); } catch (RemoteException e) { throw e.rethrowFromSystemServer(); + } catch (ServiceSpecificException e) { + throw convertServiceException(e); } } @@ -3279,6 +3305,8 @@ public class ConnectivityManager { mService.pendingListenForNetwork(request.networkCapabilities, operation); } catch (RemoteException e) { throw e.rethrowFromSystemServer(); + } catch (ServiceSpecificException e) { + throw convertServiceException(e); } } diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java index 35a3c0c0d8c1..2c1796370558 100755 --- a/core/java/android/provider/Settings.java +++ b/core/java/android/provider/Settings.java @@ -9114,7 +9114,8 @@ public final class Settings { CALL_AUTO_RETRY, DOCK_AUDIO_MEDIA_ENABLED, ENCODED_SURROUND_OUTPUT, - LOW_POWER_MODE_TRIGGER_LEVEL + LOW_POWER_MODE_TRIGGER_LEVEL, + BLUETOOTH_ON }; // Populated lazily, guarded by class object: diff --git a/core/java/android/util/MemoryIntArray.java b/core/java/android/util/MemoryIntArray.java index 0d62054825e8..b72e783c2832 100644 --- a/core/java/android/util/MemoryIntArray.java +++ b/core/java/android/util/MemoryIntArray.java @@ -53,7 +53,7 @@ public final class MemoryIntArray implements Parcelable, Closeable { private final boolean mIsOwner; private final long mMemoryAddr; - private int mFd; + private int mFd = -1; /** * Creates a new instance. diff --git a/core/java/com/android/internal/os/ZygoteConnection.java b/core/java/com/android/internal/os/ZygoteConnection.java index 527582be3c02..91429a609288 100644 --- a/core/java/com/android/internal/os/ZygoteConnection.java +++ b/core/java/com/android/internal/os/ZygoteConnection.java @@ -717,14 +717,6 @@ class ZygoteConnection { public static void applyInvokeWithSystemProperty(Arguments args) { if (args.invokeWith == null && args.niceName != null) { String property = "wrap." + args.niceName; - if (property.length() > 31) { - // Properties with a trailing "." are illegal. - if (property.charAt(30) != '.') { - property = property.substring(0, 31); - } else { - property = property.substring(0, 30); - } - } args.invokeWith = SystemProperties.get(property); if (args.invokeWith != null && args.invokeWith.length() == 0) { args.invokeWith = null; diff --git a/core/jni/com_android_internal_os_Zygote.cpp b/core/jni/com_android_internal_os_Zygote.cpp index 6000fb56299d..d73e7dd50140 100644 --- a/core/jni/com_android_internal_os_Zygote.cpp +++ b/core/jni/com_android_internal_os_Zygote.cpp @@ -27,6 +27,7 @@ #include <fcntl.h> #include <grp.h> #include <inttypes.h> +#include <malloc.h> #include <mntent.h> #include <paths.h> #include <signal.h> @@ -519,6 +520,9 @@ static pid_t ForkAndSpecializeCommon(JNIEnv* env, uid_t uid, gid_t gid, jintArra // The child process. gMallocLeakZygoteChild = 1; + // Set the jemalloc decay time to 1. + mallopt(M_DECAY_TIME, 1); + // Clean up any descriptors which must be closed immediately DetachDescriptors(env, fdsToClose); diff --git a/core/res/res/values-mcc311-mnc480/config.xml b/core/res/res/values-mcc311-mnc480/config.xml index 10166a545092..0cafed68efed 100755 --- a/core/res/res/values-mcc311-mnc480/config.xml +++ b/core/res/res/values-mcc311-mnc480/config.xml @@ -48,9 +48,6 @@ provisioning, availability etc --> <bool name="config_carrier_vt_available">true</bool> - <!-- Flag specifying whether VoLTE availability is based on provisioning --> - <bool name="config_carrier_volte_provisioned">true</bool> - <bool name="config_auto_attach_data_on_creation">false</bool> <!--Thresholds for LTE dbm in status bar--> diff --git a/core/res/res/values/config.xml b/core/res/res/values/config.xml index 22a1a3663342..37d03ad0ec1d 100644 --- a/core/res/res/values/config.xml +++ b/core/res/res/values/config.xml @@ -2328,9 +2328,6 @@ provisioning, availability etc --> <bool name="config_carrier_volte_available">false</bool> - <!-- Flag specifying whether VoLTE availability is based on provisioning --> - <bool name="config_carrier_volte_provisioned">false</bool> - <!-- Flag specifying whether VoLTE TTY is supported --> <bool name="config_carrier_volte_tty_supported">true</bool> diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml index ea89cc15c0b0..f3ce7190ca7f 100644 --- a/core/res/res/values/symbols.xml +++ b/core/res/res/values/symbols.xml @@ -2262,7 +2262,6 @@ <java-symbol type="bool" name="imsServiceAllowTurnOff" /> <java-symbol type="bool" name="config_device_volte_available" /> <java-symbol type="bool" name="config_carrier_volte_available" /> - <java-symbol type="bool" name="config_carrier_volte_provisioned" /> <java-symbol type="bool" name="config_carrier_volte_tty_supported" /> <java-symbol type="bool" name="config_device_vt_available" /> <java-symbol type="bool" name="config_device_respects_hold_carrier_config" /> diff --git a/core/tests/utiltests/Android.mk b/core/tests/utiltests/Android.mk index faf04b119e7b..e69a2cc53f20 100644 --- a/core/tests/utiltests/Android.mk +++ b/core/tests/utiltests/Android.mk @@ -17,7 +17,8 @@ LOCAL_JNI_SHARED_LIBRARIES := libmemoryintarraytest libcutils libc++ LOCAL_STATIC_JAVA_LIBRARIES := \ android-support-test \ frameworks-base-testutils \ - mockito-target + mockito-target \ + legacy-android-tests LOCAL_JAVA_LIBRARIES := android.test.runner @@ -27,4 +28,4 @@ LOCAL_CERTIFICATE := platform include $(BUILD_PACKAGE) -include $(call all-makefiles-under,$(LOCAL_PATH))
\ No newline at end of file +include $(call all-makefiles-under,$(LOCAL_PATH)) diff --git a/data/etc/platform.xml b/data/etc/platform.xml index e46f1666282e..ae0c8a02b48b 100644 --- a/data/etc/platform.xml +++ b/data/etc/platform.xml @@ -45,6 +45,7 @@ <permission name="android.permission.BLUETOOTH_STACK" > <group gid="bluetooth" /> <group gid="wakelock" /> + <group gid="uhid" /> </permission> <permission name="android.permission.NET_TUNNELING" > diff --git a/legacy-test/Android.mk b/legacy-test/Android.mk index 0835cadbe698..8efda2ad0c20 100644 --- a/legacy-test/Android.mk +++ b/legacy-test/Android.mk @@ -20,9 +20,11 @@ LOCAL_PATH:= $(call my-dir) # ============================= # This contains the junit.framework and android.test classes that were in # Android API level 25 excluding those from android.test.runner. +# Also contains the com.android.internal.util.Predicate[s] classes. include $(CLEAR_VARS) LOCAL_SRC_FILES := $(call all-java-files-under, src) + LOCAL_MODULE := legacy-test LOCAL_NO_STANDARD_LIBRARIES := true LOCAL_JAVA_LIBRARIES := core-oj core-libart framework @@ -30,20 +32,35 @@ LOCAL_JAVA_LIBRARIES := core-oj core-libart framework include $(BUILD_JAVA_LIBRARY) # Build the legacy-android-test library -# ============================= +# ===================================== # This contains the android.test classes that were in Android API level 25, # including those from android.test.runner. +# Also contains the com.android.internal.util.Predicate[s] classes. include $(CLEAR_VARS) LOCAL_SRC_FILES := \ $(call all-java-files-under, src/android) \ - $(call all-java-files-under, ../test-runner/src/android) + $(call all-java-files-under, ../test-runner/src/android) \ + $(call all-java-files-under, src/com) LOCAL_MODULE := legacy-android-test LOCAL_NO_STANDARD_LIBRARIES := true LOCAL_JAVA_LIBRARIES := core-oj core-libart framework junit include $(BUILD_STATIC_JAVA_LIBRARY) +# Build the legacy-android-tests library +# ====================================== +include $(CLEAR_VARS) + +LOCAL_SRC_FILES := \ + $(call all-java-files-under, tests) +LOCAL_MODULE := legacy-android-tests +LOCAL_NO_STANDARD_LIBRARIES := true +LOCAL_JAVA_LIBRARIES := core-oj core-libart framework junit +LOCAL_STATIC_JAVA_LIBRARIES := legacy-android-test + +include $(BUILD_STATIC_JAVA_LIBRARY) + ifeq ($(HOST_OS),linux) # Build the legacy-performance-test-hostdex library # ================================================= diff --git a/core/java/com/android/internal/util/Predicate.java b/legacy-test/src/com/android/internal/util/Predicate.java index 1b5eaff67b87..1b5eaff67b87 100644 --- a/core/java/com/android/internal/util/Predicate.java +++ b/legacy-test/src/com/android/internal/util/Predicate.java diff --git a/core/java/com/android/internal/util/Predicates.java b/legacy-test/src/com/android/internal/util/Predicates.java index c006564f129a..fe1ff1529138 100644 --- a/core/java/com/android/internal/util/Predicates.java +++ b/legacy-test/src/com/android/internal/util/Predicates.java @@ -21,6 +21,8 @@ import java.util.Arrays; /** * Predicates contains static methods for creating the standard set of * {@code Predicate} objects. + * + * @hide */ public class Predicates { diff --git a/core/tests/utiltests/src/com/android/internal/util/PredicatesTest.java b/legacy-test/tests/com/android/internal/util/PredicatesTest.java index c46ff051dd33..c46ff051dd33 100644 --- a/core/tests/utiltests/src/com/android/internal/util/PredicatesTest.java +++ b/legacy-test/tests/com/android/internal/util/PredicatesTest.java diff --git a/packages/CaptivePortalLogin/src/com/android/captiveportallogin/CaptivePortalLoginActivity.java b/packages/CaptivePortalLogin/src/com/android/captiveportallogin/CaptivePortalLoginActivity.java index 6394c64b74cc..34465e92a1ef 100644 --- a/packages/CaptivePortalLogin/src/com/android/captiveportallogin/CaptivePortalLoginActivity.java +++ b/packages/CaptivePortalLogin/src/com/android/captiveportallogin/CaptivePortalLoginActivity.java @@ -122,6 +122,11 @@ public class CaptivePortalLoginActivity extends Activity { WebSettings webSettings = myWebView.getSettings(); webSettings.setJavaScriptEnabled(true); webSettings.setMixedContentMode(WebSettings.MIXED_CONTENT_COMPATIBILITY_MODE); + webSettings.setUseWideViewPort(true); + webSettings.setLoadWithOverviewMode(true); + webSettings.setSupportZoom(true); + webSettings.setBuiltInZoomControls(true); + webSettings.setDisplayZoomControls(false); mWebViewClient = new MyWebViewClient(); myWebView.setWebViewClient(mWebViewClient); myWebView.setWebChromeClient(new MyWebChromeClient()); diff --git a/packages/CarrierDefaultApp/src/com/android/carrierdefaultapp/CaptivePortalLoginActivity.java b/packages/CarrierDefaultApp/src/com/android/carrierdefaultapp/CaptivePortalLoginActivity.java index ec4c00ed6117..61b3122f5f7d 100644 --- a/packages/CarrierDefaultApp/src/com/android/carrierdefaultapp/CaptivePortalLoginActivity.java +++ b/packages/CarrierDefaultApp/src/com/android/carrierdefaultapp/CaptivePortalLoginActivity.java @@ -96,6 +96,10 @@ public class CaptivePortalLoginActivity extends Activity { WebSettings webSettings = mWebView.getSettings(); webSettings.setJavaScriptEnabled(true); webSettings.setMixedContentMode(WebSettings.MIXED_CONTENT_COMPATIBILITY_MODE); + webSettings.setUseWideViewPort(true); + webSettings.setLoadWithOverviewMode(true); + webSettings.setSupportZoom(true); + webSettings.setBuiltInZoomControls(true); mWebViewClient = new MyWebViewClient(); mWebView.setWebViewClient(mWebViewClient); mWebView.setWebChromeClient(new MyWebChromeClient()); diff --git a/packages/SettingsProvider/src/com/android/providers/settings/SettingsHelper.java b/packages/SettingsProvider/src/com/android/providers/settings/SettingsHelper.java index bf48e5de1da3..75ae835b81cf 100644 --- a/packages/SettingsProvider/src/com/android/providers/settings/SettingsHelper.java +++ b/packages/SettingsProvider/src/com/android/providers/settings/SettingsHelper.java @@ -62,11 +62,12 @@ public class SettingsHelper { */ private static final ArraySet<String> sBroadcastOnRestore; static { - sBroadcastOnRestore = new ArraySet<String>(4); + sBroadcastOnRestore = new ArraySet<String>(5); sBroadcastOnRestore.add(Settings.Secure.ENABLED_NOTIFICATION_LISTENERS); sBroadcastOnRestore.add(Settings.Secure.ENABLED_VR_LISTENERS); sBroadcastOnRestore.add(Settings.Secure.ENABLED_ACCESSIBILITY_SERVICES); sBroadcastOnRestore.add(Settings.Secure.ENABLED_INPUT_METHODS); + sBroadcastOnRestore.add(Settings.Global.BLUETOOTH_ON); } private interface SettingsLookup { diff --git a/services/core/Android.mk b/services/core/Android.mk index 689c97976cc0..f9b0d2f05c94 100644 --- a/services/core/Android.mk +++ b/services/core/Android.mk @@ -18,10 +18,18 @@ LOCAL_SRC_FILES += \ LOCAL_AIDL_INCLUDES += \ system/netd/server/binder -LOCAL_JAVA_LIBRARIES := services.net -LOCAL_STATIC_JAVA_LIBRARIES := tzdata_shared2 tzdata_update2 LOCAL_PROTOC_OPTIMIZE_TYPE := nano +LOCAL_JAVA_LIBRARIES := \ + services.net \ + android.hidl.manager-V1.0-java \ + +LOCAL_STATIC_JAVA_LIBRARIES := \ + tzdata_shared2 \ + tzdata_update2 \ + android.hidl.base-V1.0-java-static \ + android.hardware.tetheroffload.control-V1.0-java-static \ + ifneq ($(INCREMENTAL_BUILDS),) LOCAL_PROGUARD_ENABLED := disabled LOCAL_JACK_ENABLED := incremental diff --git a/services/core/java/com/android/server/BluetoothManagerService.java b/services/core/java/com/android/server/BluetoothManagerService.java index 1262d88be8e1..ba1befdf8175 100644 --- a/services/core/java/com/android/server/BluetoothManagerService.java +++ b/services/core/java/com/android/server/BluetoothManagerService.java @@ -90,6 +90,7 @@ class BluetoothManagerService extends IBluetoothManager.Stub { private static final String REASON_SYSTEM_BOOT = "system boot"; private static final String REASON_UNEXPECTED = "unexpected crash"; private static final String REASON_USER_SWITCH = "user switch"; + private static final String REASON_RESTORE_USER_SETTING = "restore user setting"; private static final int TIMEOUT_BIND_MS = 3000; //Maximum msec to wait for a bind //Maximum msec to wait for service restart @@ -118,6 +119,10 @@ class BluetoothManagerService extends IBluetoothManager.Stub { private static final int MESSAGE_USER_UNLOCKED = 301; private static final int MESSAGE_ADD_PROXY_DELAYED = 400; private static final int MESSAGE_BIND_PROFILE_SERVICE = 401; + private static final int MESSAGE_RESTORE_USER_SETTING = 500; + + private static final int RESTORE_SETTING_TO_ON = 1; + private static final int RESTORE_SETTING_TO_OFF = 0; private static final int MAX_SAVE_RETRIES = 3; private static final int MAX_ERROR_RESTART_RETRIES = 6; @@ -315,6 +320,26 @@ class BluetoothManagerService extends IBluetoothManager.Stub { } else { if (DBG) Slog.e(TAG, "No Bluetooth Adapter address parameter found"); } + } else if (Intent.ACTION_SETTING_RESTORED.equals(action)) { + final String name = intent.getStringExtra(Intent.EXTRA_SETTING_NAME); + if (Settings.Global.BLUETOOTH_ON.equals(name)) { + // The Bluetooth On state may be changed during system restore. + final String prevValue = intent.getStringExtra( + Intent.EXTRA_SETTING_PREVIOUS_VALUE); + final String newValue = intent.getStringExtra( + Intent.EXTRA_SETTING_NEW_VALUE); + + if (DBG) Slog.d(TAG, "ACTION_SETTING_RESTORED with BLUETOOTH_ON, prevValue=" + + prevValue + ", newValue=" + newValue); + + if ((newValue != null) && (prevValue != null) && !prevValue.equals(newValue)) { + Message msg = mHandler.obtainMessage(MESSAGE_RESTORE_USER_SETTING, + newValue.equals("0") ? + RESTORE_SETTING_TO_OFF : + RESTORE_SETTING_TO_ON, 0); + mHandler.sendMessage(msg); + } + } } } }; @@ -348,12 +373,14 @@ class BluetoothManagerService extends IBluetoothManager.Stub { registerForBleScanModeChange(); mCallbacks = new RemoteCallbackList<IBluetoothManagerCallback>(); mStateChangeCallbacks = new RemoteCallbackList<IBluetoothStateChangeCallback>(); - IntentFilter filter = new IntentFilter(BluetoothAdapter.ACTION_LOCAL_NAME_CHANGED); - filter.setPriority(IntentFilter.SYSTEM_HIGH_PRIORITY); - mContext.registerReceiver(mReceiver, filter); - filter = new IntentFilter(BluetoothAdapter.ACTION_BLUETOOTH_ADDRESS_CHANGED); + + IntentFilter filter = new IntentFilter(); + filter.addAction(BluetoothAdapter.ACTION_LOCAL_NAME_CHANGED); + filter.addAction(BluetoothAdapter.ACTION_BLUETOOTH_ADDRESS_CHANGED); + filter.addAction(Intent.ACTION_SETTING_RESTORED); filter.setPriority(IntentFilter.SYSTEM_HIGH_PRIORITY); mContext.registerReceiver(mReceiver, filter); + loadStoredNameAndAddress(); if (isBluetoothPersistedStateOn()) { if (DBG) Slog.d(TAG, "Startup: Bluetooth persisted state is ON."); @@ -1424,6 +1451,20 @@ class BluetoothManagerService extends IBluetoothManager.Stub { } break; + case MESSAGE_RESTORE_USER_SETTING: + try { + if ((msg.arg1 == RESTORE_SETTING_TO_OFF) && mEnable) { + if (DBG) Slog.d(TAG, "Restore Bluetooth state to disabled"); + disable(REASON_RESTORE_USER_SETTING, true); + } else if ((msg.arg1 == RESTORE_SETTING_TO_ON) && !mEnable) { + if (DBG) Slog.d(TAG, "Restore Bluetooth state to enabled"); + enable(REASON_RESTORE_USER_SETTING); + } + } catch (RemoteException e) { + Slog.e(TAG,"Unable to change Bluetooth On setting", e); + } + break; + case MESSAGE_REGISTER_ADAPTER: { IBluetoothManagerCallback callback = (IBluetoothManagerCallback) msg.obj; @@ -1658,7 +1699,7 @@ class BluetoothManagerService extends IBluetoothManager.Stub { mHandler.removeMessages(MESSAGE_USER_SWITCHED); /* disable and enable BT when detect a user switch */ - if (mEnable && mBluetooth != null) { + if (mBluetooth != null && isEnabled()) { try { mBluetoothLock.readLock().lock(); if (mBluetooth != null) { @@ -1727,6 +1768,8 @@ class BluetoothManagerService extends IBluetoothManager.Stub { mState = BluetoothAdapter.STATE_OFF; // enable addActiveLog(REASON_USER_SWITCH, true); + // mEnable flag could have been reset on disableBLE. Reenable it. + mEnable = true; handleEnable(mQuietEnable); } else if (mBinding || mBluetooth != null) { Message userMsg = mHandler.obtainMessage(MESSAGE_USER_SWITCHED); diff --git a/services/core/java/com/android/server/ConnectivityService.java b/services/core/java/com/android/server/ConnectivityService.java index 88bc54d26755..47026d6815f4 100644 --- a/services/core/java/com/android/server/ConnectivityService.java +++ b/services/core/java/com/android/server/ConnectivityService.java @@ -98,6 +98,7 @@ import android.os.PowerManager; import android.os.Process; import android.os.RemoteException; import android.os.ResultReceiver; +import android.os.ServiceSpecificException; import android.os.SystemClock; import android.os.UserHandle; import android.os.UserManager; @@ -144,6 +145,7 @@ import com.android.server.connectivity.NetworkNotificationManager.NotificationTy import com.android.server.connectivity.PacManager; import com.android.server.connectivity.PermissionMonitor; import com.android.server.connectivity.Tethering; +import com.android.server.connectivity.tethering.TetheringDependencies; import com.android.server.connectivity.Vpn; import com.android.server.net.BaseNetworkObserver; import com.android.server.net.LockdownVpnTracker; @@ -486,7 +488,7 @@ public class ConnectivityService extends IConnectivityManager.Stub new ArrayDeque<ValidationLog>(MAX_VALIDATION_LOGS); private void addValidationLogs(ReadOnlyLocalLog log, Network network, String networkExtraInfo) { - synchronized(mValidationLogs) { + synchronized (mValidationLogs) { while (mValidationLogs.size() >= MAX_VALIDATION_LOGS) { mValidationLogs.removeLast(); } @@ -801,8 +803,7 @@ public class ConnectivityService extends IConnectivityManager.Stub mTestMode = mSystemProperties.get("cm.test.mode").equals("true") && mSystemProperties.get("ro.build.type").equals("eng"); - mTethering = new Tethering(mContext, mNetd, statsService, mPolicyManager, - IoThread.get().getLooper(), new MockableSystemProperties()); + mTethering = makeTethering(); mPermissionMonitor = new PermissionMonitor(mContext, mNetd); @@ -852,6 +853,14 @@ public class ConnectivityService extends IConnectivityManager.Stub mMultinetworkPolicyTracker.start(); } + private Tethering makeTethering() { + // TODO: Move other elements into @Overridden getters. + final TetheringDependencies deps = new TetheringDependencies(); + return new Tethering(mContext, mNetd, mStatsService, mPolicyManager, + IoThread.get().getLooper(), new MockableSystemProperties(), + deps); + } + private NetworkRequest createInternetRequestForTransport( int transportType, NetworkRequest.Type type) { NetworkCapabilities netCap = new NetworkCapabilities(); @@ -1670,7 +1679,7 @@ public class ConnectivityService extends IConnectivityManager.Stub } private void sendStickyBroadcast(Intent intent) { - synchronized(this) { + synchronized (this) { if (!mSystemReady) { mInitialBroadcast = new Intent(intent); } @@ -1711,7 +1720,7 @@ public class ConnectivityService extends IConnectivityManager.Stub void systemReady() { loadGlobalProxy(); - synchronized(this) { + synchronized (this) { mSystemReady = true; if (mInitialBroadcast != null) { mContext.sendStickyBroadcastAsUser(mInitialBroadcast, UserHandle.ALL); @@ -3493,7 +3502,7 @@ public class ConnectivityService extends IConnectivityManager.Stub enforceCrossUserPermission(userId); throwIfLockdownEnabled(); - synchronized(mVpns) { + synchronized (mVpns) { Vpn vpn = mVpns.get(userId); if (vpn != null) { return vpn.prepare(oldPackage, newPackage); @@ -3520,7 +3529,7 @@ public class ConnectivityService extends IConnectivityManager.Stub public void setVpnPackageAuthorization(String packageName, int userId, boolean authorized) { enforceCrossUserPermission(userId); - synchronized(mVpns) { + synchronized (mVpns) { Vpn vpn = mVpns.get(userId); if (vpn != null) { vpn.setPackageAuthorization(packageName, authorized); @@ -3539,7 +3548,7 @@ public class ConnectivityService extends IConnectivityManager.Stub public ParcelFileDescriptor establishVpn(VpnConfig config) { throwIfLockdownEnabled(); int user = UserHandle.getUserId(Binder.getCallingUid()); - synchronized(mVpns) { + synchronized (mVpns) { return mVpns.get(user).establish(config); } } @@ -3556,7 +3565,7 @@ public class ConnectivityService extends IConnectivityManager.Stub throw new IllegalStateException("Missing active network connection"); } int user = UserHandle.getUserId(Binder.getCallingUid()); - synchronized(mVpns) { + synchronized (mVpns) { mVpns.get(user).startLegacyVpn(profile, mKeyStore, egress); } } @@ -3570,7 +3579,7 @@ public class ConnectivityService extends IConnectivityManager.Stub public LegacyVpnInfo getLegacyVpnInfo(int userId) { enforceCrossUserPermission(userId); - synchronized(mVpns) { + synchronized (mVpns) { return mVpns.get(userId).getLegacyVpnInfo(); } } @@ -3586,7 +3595,7 @@ public class ConnectivityService extends IConnectivityManager.Stub return new VpnInfo[0]; } - synchronized(mVpns) { + synchronized (mVpns) { List<VpnInfo> infoList = new ArrayList<>(); for (int i = 0; i < mVpns.size(); i++) { VpnInfo info = createVpnInfo(mVpns.valueAt(i)); @@ -3634,7 +3643,7 @@ public class ConnectivityService extends IConnectivityManager.Stub @Override public VpnConfig getVpnConfig(int userId) { enforceCrossUserPermission(userId); - synchronized(mVpns) { + synchronized (mVpns) { Vpn vpn = mVpns.get(userId); if (vpn != null) { return vpn.getVpnConfig(); @@ -3668,7 +3677,7 @@ public class ConnectivityService extends IConnectivityManager.Stub return true; } int user = UserHandle.getUserId(Binder.getCallingUid()); - synchronized(mVpns) { + synchronized (mVpns) { Vpn vpn = mVpns.get(user); if (vpn == null) { Slog.w(TAG, "VPN for user " + user + " not ready yet. Skipping lockdown"); @@ -3903,7 +3912,7 @@ public class ConnectivityService extends IConnectivityManager.Stub } private void onUserStart(int userId) { - synchronized(mVpns) { + synchronized (mVpns) { Vpn userVpn = mVpns.get(userId); if (userVpn != null) { loge("Starting user already has a VPN"); @@ -3918,7 +3927,7 @@ public class ConnectivityService extends IConnectivityManager.Stub } private void onUserStop(int userId) { - synchronized(mVpns) { + synchronized (mVpns) { Vpn userVpn = mVpns.get(userId); if (userVpn == null) { loge("Stopped user has no VPN"); @@ -3930,7 +3939,7 @@ public class ConnectivityService extends IConnectivityManager.Stub } private void onUserAdded(int userId) { - synchronized(mVpns) { + synchronized (mVpns) { final int vpnsSize = mVpns.size(); for (int i = 0; i < vpnsSize; i++) { Vpn vpn = mVpns.valueAt(i); @@ -3940,7 +3949,7 @@ public class ConnectivityService extends IConnectivityManager.Stub } private void onUserRemoved(int userId) { - synchronized(mVpns) { + synchronized (mVpns) { final int vpnsSize = mVpns.size(); for (int i = 0; i < vpnsSize; i++) { Vpn vpn = mVpns.valueAt(i); @@ -4064,7 +4073,8 @@ public class ConnectivityService extends IConnectivityManager.Stub synchronized (mUidToNetworkRequestCount) { int networkRequests = mUidToNetworkRequestCount.get(mUid, 0) + 1; if (networkRequests >= MAX_NETWORK_REQUESTS_PER_UID) { - throw new IllegalArgumentException("Too many NetworkRequests filed"); + throw new ServiceSpecificException( + ConnectivityManager.Errors.TOO_MANY_REQUESTS); } mUidToNetworkRequestCount.put(mUid, networkRequests); } diff --git a/services/core/java/com/android/server/NetworkTimeUpdateService.java b/services/core/java/com/android/server/NetworkTimeUpdateService.java index b64c65dd5827..9f7437ec2a3a 100644 --- a/services/core/java/com/android/server/NetworkTimeUpdateService.java +++ b/services/core/java/com/android/server/NetworkTimeUpdateService.java @@ -26,6 +26,8 @@ import android.content.IntentFilter; import android.content.pm.PackageManager; import android.database.ContentObserver; import android.net.ConnectivityManager; +import android.net.ConnectivityManager.NetworkCallback; +import android.net.Network; import android.os.Binder; import android.os.Handler; import android.os.HandlerThread; @@ -73,6 +75,7 @@ public class NetworkTimeUpdateService extends Binder { private long mNitzTimeSetTime = NOT_SET; // TODO: Have a way to look up the timezone we are in private long mNitzZoneSetTime = NOT_SET; + private Network mDefaultNetwork = null; private Context mContext; private TrustedTime mTime; @@ -82,6 +85,8 @@ public class NetworkTimeUpdateService extends Binder { private AlarmManager mAlarmManager; private PendingIntent mPendingPollIntent; private SettingsObserver mSettingsObserver; + private ConnectivityManager mCM; + private NetworkTimeUpdateCallback mNetworkTimeUpdateCallback; // The last time that we successfully fetched the NTP time. private long mLastNtpFetchTime = NOT_SET; private final PowerManager.WakeLock mWakeLock; @@ -103,6 +108,7 @@ public class NetworkTimeUpdateService extends Binder { mContext = context; mTime = NtpTrustedTime.getInstance(context); mAlarmManager = (AlarmManager) mContext.getSystemService(Context.ALARM_SERVICE); + mCM = (ConnectivityManager) mContext.getSystemService(Context.CONNECTIVITY_SERVICE); Intent pollIntent = new Intent(ACTION_POLL, null); mPendingPollIntent = PendingIntent.getBroadcast(mContext, POLL_REQUEST, pollIntent, 0); @@ -123,13 +129,12 @@ public class NetworkTimeUpdateService extends Binder { public void systemRunning() { registerForTelephonyIntents(); registerForAlarms(); - registerForConnectivityIntents(); HandlerThread thread = new HandlerThread(TAG); thread.start(); mHandler = new MyHandler(thread.getLooper()); - // Check the network time on the new thread - mHandler.obtainMessage(EVENT_POLL_NETWORK_TIME).sendToTarget(); + mNetworkTimeUpdateCallback = new NetworkTimeUpdateCallback(); + mCM.registerDefaultNetworkCallback(mNetworkTimeUpdateCallback, mHandler); mSettingsObserver = new SettingsObserver(mHandler, EVENT_AUTO_TIME_CHANGED); mSettingsObserver.observe(mContext); @@ -152,15 +157,10 @@ public class NetworkTimeUpdateService extends Binder { }, new IntentFilter(ACTION_POLL)); } - private void registerForConnectivityIntents() { - IntentFilter intentFilter = new IntentFilter(); - intentFilter.addAction(ConnectivityManager.CONNECTIVITY_ACTION); - mContext.registerReceiver(mConnectivityReceiver, intentFilter); - } - private void onPollNetworkTime(int event) { - // If Automatic time is not set, don't bother. - if (!isAutomaticTimeRequested()) return; + // If Automatic time is not set, don't bother. Similarly, if we don't + // have any default network, don't bother. + if (!isAutomaticTimeRequested() || mDefaultNetwork == null) return; mWakeLock.acquire(); try { onPollNetworkTimeUnderWakeLock(event); @@ -262,22 +262,6 @@ public class NetworkTimeUpdateService extends Binder { } }; - /** Receiver for ConnectivityManager events */ - private BroadcastReceiver mConnectivityReceiver = new BroadcastReceiver() { - - @Override - public void onReceive(Context context, Intent intent) { - String action = intent.getAction(); - if (ConnectivityManager.CONNECTIVITY_ACTION.equals(action)) { - if (DBG) Log.d(TAG, "Received CONNECTIVITY_ACTION "); - // Don't bother checking if we have connectivity, NtpTrustedTime does that for us. - Message message = mHandler.obtainMessage(EVENT_NETWORK_CHANGED); - // Send with a short delay to make sure the network is ready for use - mHandler.sendMessageDelayed(message, NETWORK_CHANGE_EVENT_DELAY_MS); - } - } - }; - /** Handler to do the network accesses on */ private class MyHandler extends Handler { @@ -297,6 +281,21 @@ public class NetworkTimeUpdateService extends Binder { } } + private class NetworkTimeUpdateCallback extends NetworkCallback { + @Override + public void onAvailable(Network network) { + Log.d(TAG, String.format("New default network %s; checking time.", network)); + mDefaultNetwork = network; + // Running on mHandler so invoke directly. + onPollNetworkTime(EVENT_NETWORK_CHANGED); + } + + @Override + public void onLost(Network network) { + if (network.equals(mDefaultNetwork)) mDefaultNetwork = null; + } + } + /** Observer to watch for changes to the AUTO_TIME setting */ private static class SettingsObserver extends ContentObserver { diff --git a/services/core/java/com/android/server/connectivity/Tethering.java b/services/core/java/com/android/server/connectivity/Tethering.java index 4dae36411844..9c551dda7c71 100644 --- a/services/core/java/com/android/server/connectivity/Tethering.java +++ b/services/core/java/com/android/server/connectivity/Tethering.java @@ -81,6 +81,7 @@ import com.android.server.connectivity.tethering.OffloadController; import com.android.server.connectivity.tethering.SimChangeListener; import com.android.server.connectivity.tethering.TetherInterfaceStateMachine; import com.android.server.connectivity.tethering.TetheringConfiguration; +import com.android.server.connectivity.tethering.TetheringDependencies; import com.android.server.connectivity.tethering.UpstreamNetworkMonitor; import com.android.server.net.BaseNetworkObserver; @@ -178,7 +179,8 @@ public class Tethering extends BaseNetworkObserver implements IControlsTethering public Tethering(Context context, INetworkManagementService nmService, INetworkStatsService statsService, INetworkPolicyManager policyManager, - Looper looper, MockableSystemProperties systemProperties) { + Looper looper, MockableSystemProperties systemProperties, + TetheringDependencies deps) { mLocalLog.log("CONSTRUCTED"); mContext = context; mNMService = nmService; @@ -194,7 +196,8 @@ public class Tethering extends BaseNetworkObserver implements IControlsTethering mTetherMasterSM = new TetherMasterSM("TetherMaster", mLooper); mTetherMasterSM.start(); - mOffloadController = new OffloadController(mTetherMasterSM.getHandler()); + mOffloadController = new OffloadController(mTetherMasterSM.getHandler(), + deps.getOffloadHardwareInterface()); mUpstreamNetworkMonitor = new UpstreamNetworkMonitor( mContext, mTetherMasterSM, TetherMasterSM.EVENT_UPSTREAM_CALLBACK); mForwardedDownstreams = new HashSet<>(); @@ -1474,7 +1477,8 @@ public class Tethering extends BaseNetworkObserver implements IControlsTethering handleInterfaceServingStateInactive(who); if (mNotifyList.isEmpty()) { - // transitions appropriately + // This transitions us out of TetherModeAliveState, + // either to InitialState or an error state. turnOffMasterTetherSettings(); break; } diff --git a/services/core/java/com/android/server/connectivity/tethering/OffloadController.java b/services/core/java/com/android/server/connectivity/tethering/OffloadController.java index 220e7514facc..6c93730974d4 100644 --- a/services/core/java/com/android/server/connectivity/tethering/OffloadController.java +++ b/services/core/java/com/android/server/connectivity/tethering/OffloadController.java @@ -18,10 +18,12 @@ package com.android.server.connectivity.tethering; import android.net.LinkProperties; import android.os.Handler; +import android.os.RemoteException; import android.util.Log; /** - * A wrapper around hardware offload interface. + * A class to encapsulate the business logic of programming the tethering + * hardware offload interface. * * @hide */ @@ -29,25 +31,48 @@ public class OffloadController { private static final String TAG = OffloadController.class.getSimpleName(); private final Handler mHandler; + private final OffloadHardwareInterface mHwInterface; + private boolean mConfigInitialized; + private boolean mControlInitialized; private LinkProperties mUpstreamLinkProperties; - public OffloadController(Handler h) { + public OffloadController(Handler h, OffloadHardwareInterface hwi) { mHandler = h; + mHwInterface = hwi; } public void start() { - // TODO: initOffload() and configure callbacks to be handled on our - // preferred Handler. - Log.d(TAG, "tethering offload not supported"); + if (started()) return; + + if (!mConfigInitialized) { + mConfigInitialized = mHwInterface.initOffloadConfig(); + if (!mConfigInitialized) { + Log.d(TAG, "tethering offload config not supported"); + return; + } + } + + // TODO: Create and register ITetheringOffloadCallback. + mControlInitialized = mHwInterface.initOffloadControl(); } public void stop() { - // TODO: stopOffload(). mUpstreamLinkProperties = null; + mHwInterface.stopOffloadControl(); + mControlInitialized = false; + mConfigInitialized = false; } public void setUpstreamLinkProperties(LinkProperties lp) { + if (!started()) return; + // TODO: setUpstreamParameters(). mUpstreamLinkProperties = lp; } + + // TODO: public void addDownStream(...) + + private boolean started() { + return mConfigInitialized && mControlInitialized; + } } diff --git a/services/core/java/com/android/server/connectivity/tethering/OffloadHardwareInterface.java b/services/core/java/com/android/server/connectivity/tethering/OffloadHardwareInterface.java new file mode 100644 index 000000000000..87fc491b0bdd --- /dev/null +++ b/services/core/java/com/android/server/connectivity/tethering/OffloadHardwareInterface.java @@ -0,0 +1,77 @@ +/* + * 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 com.android.server.connectivity.tethering; + +import android.hardware.tetheroffload.control.V1_0.IOffloadControl; +import android.hardware.tetheroffload.control.V1_0.IOffloadControl.stopOffloadCallback; +import android.os.RemoteException; +import android.util.Log; + + +/** + * Capture tethering dependencies, for injection. + * + * @hide + */ +public class OffloadHardwareInterface { + private static final String TAG = OffloadHardwareInterface.class.getSimpleName(); + + private static native boolean configOffload(); + + private IOffloadControl mOffloadControl; + + public OffloadHardwareInterface() {} + + public boolean initOffloadConfig() { + return configOffload(); + } + + // TODO: Extend this to take a TetheringControlCallback for registration. + public boolean initOffloadControl() { + if (mOffloadControl == null) { + try { + mOffloadControl = IOffloadControl.getService(); + } catch (RemoteException e) { + Log.d(TAG, "tethering offload control not supported: " + e); + return false; + } + } + + // TODO: call mOffloadControl.initOffload(...callback...); + + return true; + } + + public void stopOffloadControl() { + if (mOffloadControl == null) return; + + try { + final stopOffloadCallback cb = new stopOffloadCallback() { + @Override + public void onValues(boolean success, String errMsg) { + if (success) return; + + Log.e(TAG, "stopOffload failed: " + errMsg); + } + }; + mOffloadControl.stopOffload(cb); + } catch (RemoteException e) { + Log.d(TAG, "failed to stopOffload: " + e); + } + mOffloadControl = null; + } +} diff --git a/services/core/java/com/android/server/connectivity/tethering/TetheringConfiguration.java b/services/core/java/com/android/server/connectivity/tethering/TetheringConfiguration.java index d38beb375fa1..44c61f0160e7 100644 --- a/services/core/java/com/android/server/connectivity/tethering/TetheringConfiguration.java +++ b/services/core/java/com/android/server/connectivity/tethering/TetheringConfiguration.java @@ -16,6 +16,7 @@ package com.android.server.connectivity.tethering; +import static android.content.Context.TELEPHONY_SERVICE; import static android.net.ConnectivityManager.TYPE_MOBILE; import static android.net.ConnectivityManager.TYPE_MOBILE_DUN; import static android.net.ConnectivityManager.TYPE_MOBILE_HIPRI; @@ -47,9 +48,9 @@ import java.util.StringJoiner; public class TetheringConfiguration { private static final String TAG = TetheringConfiguration.class.getSimpleName(); - private static final int DUN_NOT_REQUIRED = 0; - private static final int DUN_REQUIRED = 1; - private static final int DUN_UNSPECIFIED = 2; + public static final int DUN_NOT_REQUIRED = 0; + public static final int DUN_REQUIRED = 1; + public static final int DUN_UNSPECIFIED = 2; // USB is 192.168.42.1 and 255.255.255.0 // Wifi is 192.168.43.1 and 255.255.255.0 @@ -81,8 +82,9 @@ public class TetheringConfiguration { tetherableBluetoothRegexs = ctx.getResources().getStringArray( com.android.internal.R.array.config_tether_bluetooth_regexs); - isDunRequired = checkDunRequired(ctx); - preferredUpstreamIfaceTypes = getUpstreamIfaceTypes(ctx, isDunRequired); + final int dunCheck = checkDunRequired(ctx); + preferredUpstreamIfaceTypes = getUpstreamIfaceTypes(ctx, dunCheck); + isDunRequired = preferredUpstreamIfaceTypes.contains(TYPE_MOBILE_DUN); dhcpRanges = getDhcpRanges(ctx); defaultIPv4DNS = copy(DEFAULT_IPV4_DNS); @@ -138,14 +140,12 @@ public class TetheringConfiguration { pw.println(); } - private static boolean checkDunRequired(Context ctx) { - final TelephonyManager tm = ctx.getSystemService(TelephonyManager.class); - final int secureSetting = - (tm != null) ? tm.getTetherApnRequired() : DUN_UNSPECIFIED; - return (secureSetting == DUN_REQUIRED); + private static int checkDunRequired(Context ctx) { + final TelephonyManager tm = (TelephonyManager) ctx.getSystemService(TELEPHONY_SERVICE); + return (tm != null) ? tm.getTetherApnRequired() : DUN_UNSPECIFIED; } - private static Collection<Integer> getUpstreamIfaceTypes(Context ctx, boolean requiresDun) { + private static Collection<Integer> getUpstreamIfaceTypes(Context ctx, int dunCheck) { final int ifaceTypes[] = ctx.getResources().getIntArray( com.android.internal.R.array.config_tether_upstream_types); final ArrayList<Integer> upstreamIfaceTypes = new ArrayList<>(ifaceTypes.length); @@ -153,10 +153,10 @@ public class TetheringConfiguration { switch (i) { case TYPE_MOBILE: case TYPE_MOBILE_HIPRI: - if (requiresDun) continue; + if (dunCheck == DUN_REQUIRED) continue; break; case TYPE_MOBILE_DUN: - if (!requiresDun) continue; + if (dunCheck == DUN_NOT_REQUIRED) continue; break; } upstreamIfaceTypes.add(i); @@ -166,7 +166,7 @@ public class TetheringConfiguration { // of the value of |requiresDun|, cell data of one form or another is // *always* an upstream, regardless of the upstream interface types // specified by configuration resources. - if (requiresDun) { + if (dunCheck == DUN_REQUIRED) { if (!upstreamIfaceTypes.contains(TYPE_MOBILE_DUN)) { upstreamIfaceTypes.add(TYPE_MOBILE_DUN); } diff --git a/services/core/java/com/android/server/connectivity/tethering/TetheringDependencies.java b/services/core/java/com/android/server/connectivity/tethering/TetheringDependencies.java new file mode 100644 index 000000000000..be2cf080b330 --- /dev/null +++ b/services/core/java/com/android/server/connectivity/tethering/TetheringDependencies.java @@ -0,0 +1,29 @@ +/* + * 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 com.android.server.connectivity.tethering; + + +/** + * Capture tethering dependencies, for injection. + * + * @hide + */ +public class TetheringDependencies { + public OffloadHardwareInterface getOffloadHardwareInterface() { + return new OffloadHardwareInterface(); + } +} diff --git a/services/core/java/com/android/server/pm/Installer.java b/services/core/java/com/android/server/pm/Installer.java index 42a0bad302bf..f69fe64c9e49 100644 --- a/services/core/java/com/android/server/pm/Installer.java +++ b/services/core/java/com/android/server/pm/Installer.java @@ -42,22 +42,20 @@ public class Installer extends SystemService { * **************************************************************************/ /** Application should be visible to everyone */ public static final int DEXOPT_PUBLIC = 1 << 1; - /** Application wants to run in VM safe mode */ - public static final int DEXOPT_SAFEMODE = 1 << 2; /** Application wants to allow debugging of its code */ - public static final int DEXOPT_DEBUGGABLE = 1 << 3; + public static final int DEXOPT_DEBUGGABLE = 1 << 2; /** The system boot has finished */ - public static final int DEXOPT_BOOTCOMPLETE = 1 << 4; + public static final int DEXOPT_BOOTCOMPLETE = 1 << 3; /** Hint that the dexopt type is profile-guided. */ - public static final int DEXOPT_PROFILE_GUIDED = 1 << 5; + public static final int DEXOPT_PROFILE_GUIDED = 1 << 4; /** The compilation is for a secondary dex file. */ - public static final int DEXOPT_SECONDARY_DEX = 1 << 6; + public static final int DEXOPT_SECONDARY_DEX = 1 << 5; /** Ignore the result of dexoptNeeded and force compilation. */ - public static final int DEXOPT_FORCE = 1 << 7; + public static final int DEXOPT_FORCE = 1 << 6; /** Indicates that the dex file passed to dexopt in on CE storage. */ - public static final int DEXOPT_STORAGE_CE = 1 << 8; + public static final int DEXOPT_STORAGE_CE = 1 << 7; /** Indicates that the dex file passed to dexopt in on DE storage. */ - public static final int DEXOPT_STORAGE_DE = 1 << 9; + public static final int DEXOPT_STORAGE_DE = 1 << 8; // NOTE: keep in sync with installd public static final int FLAG_CLEAR_CACHE_ONLY = 1 << 8; diff --git a/services/core/java/com/android/server/pm/PackageDexOptimizer.java b/services/core/java/com/android/server/pm/PackageDexOptimizer.java index ddb36399b8b3..126ad26b909c 100644 --- a/services/core/java/com/android/server/pm/PackageDexOptimizer.java +++ b/services/core/java/com/android/server/pm/PackageDexOptimizer.java @@ -44,7 +44,6 @@ import static com.android.server.pm.Installer.DEXOPT_BOOTCOMPLETE; import static com.android.server.pm.Installer.DEXOPT_DEBUGGABLE; import static com.android.server.pm.Installer.DEXOPT_PROFILE_GUIDED; import static com.android.server.pm.Installer.DEXOPT_PUBLIC; -import static com.android.server.pm.Installer.DEXOPT_SAFEMODE; import static com.android.server.pm.Installer.DEXOPT_SECONDARY_DEX; import static com.android.server.pm.Installer.DEXOPT_FORCE; import static com.android.server.pm.Installer.DEXOPT_STORAGE_CE; @@ -381,7 +380,6 @@ public class PackageDexOptimizer { private int getDexFlags(ApplicationInfo info, String compilerFilter) { int flags = info.flags; - boolean vmSafeMode = (flags & ApplicationInfo.FLAG_VM_SAFE_MODE) != 0; boolean debuggable = (flags & ApplicationInfo.FLAG_DEBUGGABLE) != 0; // Profile guide compiled oat files should not be public. boolean isProfileGuidedFilter = isProfileGuidedCompilerFilter(compilerFilter); @@ -389,7 +387,6 @@ public class PackageDexOptimizer { int profileFlag = isProfileGuidedFilter ? DEXOPT_PROFILE_GUIDED : 0; int dexFlags = (isPublic ? DEXOPT_PUBLIC : 0) - | (vmSafeMode ? DEXOPT_SAFEMODE : 0) | (debuggable ? DEXOPT_DEBUGGABLE : 0) | profileFlag | DEXOPT_BOOTCOMPLETE; @@ -508,9 +505,6 @@ public class PackageDexOptimizer { if ((flags & DEXOPT_PUBLIC) == DEXOPT_PUBLIC) { flagsList.add("public"); } - if ((flags & DEXOPT_SAFEMODE) == DEXOPT_SAFEMODE) { - flagsList.add("safemode"); - } if ((flags & DEXOPT_SECONDARY_DEX) == DEXOPT_SECONDARY_DEX) { flagsList.add("secondary"); } diff --git a/services/core/jni/Android.mk b/services/core/jni/Android.mk index 0dbfa5674b5d..10ef1be5703a 100644 --- a/services/core/jni/Android.mk +++ b/services/core/jni/Android.mk @@ -16,6 +16,7 @@ LOCAL_SRC_FILES += \ $(LOCAL_REL_DIR)/com_android_server_am_ActivityManagerService.cpp \ $(LOCAL_REL_DIR)/com_android_server_AssetAtlasService.cpp \ $(LOCAL_REL_DIR)/com_android_server_connectivity_Vpn.cpp \ + $(LOCAL_REL_DIR)/com_android_server_connectivity_tethering_OffloadHardwareInterface.cpp \ $(LOCAL_REL_DIR)/com_android_server_ConsumerIrService.cpp \ $(LOCAL_REL_DIR)/com_android_server_HardwarePropertiesManagerService.cpp \ $(LOCAL_REL_DIR)/com_android_server_hdmi_HdmiCecController.cpp \ @@ -58,6 +59,9 @@ LOCAL_SHARED_LIBRARIES += \ liblog \ libhardware \ libhardware_legacy \ + libhidlbase \ + libhidltransport \ + libhwbinder \ libkeystore_binder \ libnativehelper \ libutils \ @@ -73,4 +77,5 @@ LOCAL_SHARED_LIBRARIES += \ libEGL \ libGLESv2 \ libnetutils \ + android.hardware.tetheroffload.config@1.0 \ diff --git a/services/core/jni/com_android_server_connectivity_tethering_OffloadHardwareInterface.cpp b/services/core/jni/com_android_server_connectivity_tethering_OffloadHardwareInterface.cpp new file mode 100644 index 000000000000..241ccf6ed166 --- /dev/null +++ b/services/core/jni/com_android_server_connectivity_tethering_OffloadHardwareInterface.cpp @@ -0,0 +1,146 @@ +/* + * 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. + */ + +#include <errno.h> +#include <error.h> +#include <hidl/HidlSupport.h> +#include <jni.h> +#include <JNIHelp.h> +#include <linux/netfilter/nfnetlink.h> +#include <linux/netlink.h> +#include <sys/socket.h> +#include <android-base/unique_fd.h> +#include <android/hardware/tetheroffload/config/1.0/IOffloadConfig.h> + +#define LOG_TAG "OffloadHardwareInterface" +#include <utils/Log.h> + +namespace android { + +using hardware::hidl_handle; +using hardware::hidl_string; +using hardware::tetheroffload::config::V1_0::IOffloadConfig; + +namespace { + +inline const sockaddr * asSockaddr(const sockaddr_nl *nladdr) { + return reinterpret_cast<const sockaddr *>(nladdr); +} + +int conntrackSocket(unsigned groups) { + base::unique_fd s(socket(AF_NETLINK, SOCK_DGRAM, NETLINK_NETFILTER)); + if (s.get() < 0) return -errno; + + const struct sockaddr_nl bind_addr = { + .nl_family = AF_NETLINK, + .nl_pad = 0, + .nl_pid = 0, + .nl_groups = groups, + }; + if (bind(s.get(), asSockaddr(&bind_addr), sizeof(bind_addr)) != 0) { + return -errno; + } + + const struct sockaddr_nl kernel_addr = { + .nl_family = AF_NETLINK, + .nl_pad = 0, + .nl_pid = 0, + .nl_groups = groups, + }; + if (connect(s.get(), asSockaddr(&kernel_addr), sizeof(kernel_addr)) != 0) { + return -errno; + } + + return s.release(); +} + +// Return a hidl_handle that owns the file descriptor owned by fd, and will +// auto-close it (otherwise there would be double-close problems). +// +// Rely upon the compiler to eliminate the constexprs used for clarity. +hidl_handle&& handleFromFileDescriptor(base::unique_fd fd) { + hidl_handle h; + + NATIVE_HANDLE_DECLARE_STORAGE(storage, 0, 0); + static constexpr int kNumFds = 1; + static constexpr int kNumInts = 0; + native_handle_t *nh = native_handle_init(storage, kNumFds, kNumInts); + nh->data[0] = fd.release(); + + static constexpr bool kTakeOwnership = true; + h.setTo(nh, kTakeOwnership); + + return std::move(h); +} + +} // namespace + +static jboolean android_server_connectivity_tethering_OffloadHardwareInterface_configOffload( + JNIEnv* /* env */) { + sp<IOffloadConfig> configInterface = IOffloadConfig::getService(); + if (configInterface.get() == nullptr) { + ALOGD("Could not find IOffloadConfig service."); + return false; + } + + // Per the IConfigOffload definition: + // + // fd1 A file descriptor bound to the following netlink groups + // (NF_NETLINK_CONNTRACK_NEW | NF_NETLINK_CONNTRACK_DESTROY). + // + // fd2 A file descriptor bound to the following netlink groups + // (NF_NETLINK_CONNTRACK_UPDATE | NF_NETLINK_CONNTRACK_DESTROY). + base::unique_fd + fd1(conntrackSocket(NFNLGRP_CONNTRACK_NEW | NFNLGRP_CONNTRACK_DESTROY)), + fd2(conntrackSocket(NFNLGRP_CONNTRACK_UPDATE | NFNLGRP_CONNTRACK_DESTROY)); + if (fd1.get() < 0 || fd2.get() < 0) { + ALOGE("Unable to create conntrack handles: %d/%s", errno, strerror(errno)); + return false; + } + + hidl_handle h1(handleFromFileDescriptor(std::move(fd1))), + h2(handleFromFileDescriptor(std::move(fd2))); + + bool rval; + hidl_string msg; + configInterface->setHandles(h1, h2, + [&rval, &msg](bool success, const hidl_string& errMsg) { + rval = success; + msg = errMsg; + }); + if (!rval) { + ALOGE("IOffloadConfig::setHandles() error: %s", msg.c_str()); + } + + return rval; +} + +/* + * JNI registration. + */ +static const JNINativeMethod gMethods[] = { + /* name, signature, funcPtr */ + { "configOffload", "()Z", + (void*) android_server_connectivity_tethering_OffloadHardwareInterface_configOffload }, +}; + +int register_android_server_connectivity_tethering_OffloadHardwareInterface(JNIEnv* env) { + return jniRegisterNativeMethods(env, + "com/android/server/connectivity/tethering/OffloadHardwareInterface", + gMethods, NELEM(gMethods)); +} + +}; // namespace android diff --git a/services/core/jni/onload.cpp b/services/core/jni/onload.cpp index d3341e517eb5..5d7291a9ddb3 100644 --- a/services/core/jni/onload.cpp +++ b/services/core/jni/onload.cpp @@ -40,6 +40,7 @@ int register_android_server_VibratorService(JNIEnv* env); int register_android_server_location_GnssLocationProvider(JNIEnv* env); int register_android_server_location_FlpHardwareProvider(JNIEnv* env); int register_android_server_connectivity_Vpn(JNIEnv* env); +int register_android_server_connectivity_tethering_OffloadHardwareInterface(JNIEnv*); int register_android_server_hdmi_HdmiCecController(JNIEnv* env); int register_android_server_tv_TvUinputBridge(JNIEnv* env); int register_android_server_tv_TvInputHal(JNIEnv* env); @@ -78,6 +79,7 @@ extern "C" jint JNI_OnLoad(JavaVM* vm, void* /* reserved */) register_android_server_location_GnssLocationProvider(env); register_android_server_location_FlpHardwareProvider(env); register_android_server_connectivity_Vpn(env); + register_android_server_connectivity_tethering_OffloadHardwareInterface(env); register_android_server_AssetAtlasService(env); register_android_server_ConsumerIrService(env); register_android_server_BatteryStatsService(env); diff --git a/services/usb/java/com/android/server/usb/UsbDeviceManager.java b/services/usb/java/com/android/server/usb/UsbDeviceManager.java index b9d22e84a88b..24cd3c78ead7 100644 --- a/services/usb/java/com/android/server/usb/UsbDeviceManager.java +++ b/services/usb/java/com/android/server/usb/UsbDeviceManager.java @@ -682,7 +682,7 @@ public class UsbDeviceManager { } // send broadcast intent only if the USB state has changed - if (!isUsbStateChanged(intent)) { + if (!isUsbStateChanged(intent) && !configChanged) { if (DEBUG) { Slog.d(TAG, "skip broadcasting " + intent + " extras: " + intent.getExtras()); } diff --git a/telephony/java/android/telephony/CarrierConfigManager.java b/telephony/java/android/telephony/CarrierConfigManager.java index e1239d08b57f..7d22a2c5f511 100644 --- a/telephony/java/android/telephony/CarrierConfigManager.java +++ b/telephony/java/android/telephony/CarrierConfigManager.java @@ -57,6 +57,13 @@ public class CarrierConfigManager { // system image, that can be added in packages/apps/CarrierConfig. /** + * This flag specifies whether VoLTE availability is based on provisioning. By default this is + * false. + */ + public static final String + KEY_CARRIER_VOLTE_PROVISIONED_BOOL = "carrier_volte_provisioned_bool"; + + /** * Flag indicating whether the Phone app should ignore EVENT_SIM_NETWORK_LOCKED * events from the Sim. * If true, this will prevent the IccNetworkDepersonalizationPanel from being shown, and @@ -1376,6 +1383,8 @@ public class CarrierConfigManager { sDefaults.putBoolean(KEY_HIDE_CARRIER_NETWORK_SETTINGS_BOOL, false); sDefaults.putBoolean(KEY_SIMPLIFIED_NETWORK_SETTINGS_BOOL, false); sDefaults.putBoolean(KEY_HIDE_SIM_LOCK_SETTINGS_BOOL, false); + + sDefaults.putBoolean(KEY_CARRIER_VOLTE_PROVISIONED_BOOL, false); sDefaults.putBoolean(KEY_IGNORE_SIM_NETWORK_LOCKED_EVENTS_BOOL, false); sDefaults.putBoolean(KEY_MDN_IS_ADDITIONAL_VOICEMAIL_NUMBER_BOOL, false); sDefaults.putBoolean(KEY_OPERATOR_SELECTION_EXPAND_BOOL, true); diff --git a/telephony/java/android/telephony/MbmsStreamingManager.java b/telephony/java/android/telephony/MbmsStreamingManager.java index fc406ee54ce8..251d5bb561d9 100644 --- a/telephony/java/android/telephony/MbmsStreamingManager.java +++ b/telephony/java/android/telephony/MbmsStreamingManager.java @@ -22,13 +22,12 @@ import android.content.Intent; import android.content.ServiceConnection; import android.content.pm.PackageManager; import android.content.pm.ResolveInfo; -import android.os.DeadObjectException; import android.os.IBinder; import android.os.RemoteException; -import android.telephony.mbms.IMbmsStreamingManagerCallback; -import android.telephony.mbms.IStreamingServiceCallback; import android.telephony.mbms.MbmsException; +import android.telephony.mbms.MbmsStreamingManagerCallback; import android.telephony.mbms.StreamingService; +import android.telephony.mbms.StreamingServiceCallback; import android.telephony.mbms.StreamingServiceInfo; import android.telephony.mbms.vendor.IMbmsStreamingService; import android.util.Log; @@ -78,14 +77,14 @@ public class MbmsStreamingManager { }; private List<ServiceListener> mServiceListeners = new LinkedList<>(); - private IMbmsStreamingManagerCallback mCallbackToApp; + private MbmsStreamingManagerCallback mCallbackToApp; private final String mAppName; private final Context mContext; private int mSubscriptionId = INVALID_SUBSCRIPTION_ID; /** @hide */ - private MbmsStreamingManager(Context context, IMbmsStreamingManagerCallback listener, + private MbmsStreamingManager(Context context, MbmsStreamingManagerCallback listener, String streamingAppName, int subscriptionId) { mContext = context; mAppName = streamingAppName; @@ -96,18 +95,18 @@ public class MbmsStreamingManager { /** * Create a new MbmsStreamingManager using the given subscription ID. * - * Note that this call will bind a remote service and that may take a bit. This - * may throw an {@link MbmsException}, indicating errors that may happen during - * the initialization or binding process. + * Note that this call will bind a remote service. You may not call this method on your app's + * main thread. This may throw an {@link MbmsException}, indicating errors that may happen + * during the initialization or binding process. * - * @param context - * @param listener - * @param streamingAppName - * @param subscriptionId - * @return + * @param context The {@link Context} to use. + * @param listener A callback object on which you wish to receive results of asynchronous + * operations. + * @param streamingAppName The name of the streaming app, as specified by the carrier. + * @param subscriptionId The subscription ID to use. */ public static MbmsStreamingManager create(Context context, - IMbmsStreamingManagerCallback listener, String streamingAppName, int subscriptionId) + MbmsStreamingManagerCallback listener, String streamingAppName, int subscriptionId) throws MbmsException { MbmsStreamingManager manager = new MbmsStreamingManager(context, listener, streamingAppName, subscriptionId); @@ -117,12 +116,10 @@ public class MbmsStreamingManager { /** * Create a new MbmsStreamingManager using the system default data subscription ID. - * - * Note that this call will bind a remote service and that may take a bit. This - * may throw an IllegalArgumentException or RemoteException. + * See {@link #create(Context, MbmsStreamingManagerCallback, String, int)}. */ public static MbmsStreamingManager create(Context context, - IMbmsStreamingManagerCallback listener, String streamingAppName) + MbmsStreamingManagerCallback listener, String streamingAppName) throws MbmsException { int subId = SubscriptionManager.getDefaultSubscriptionId(); MbmsStreamingManager manager = new MbmsStreamingManager(context, listener, @@ -156,53 +153,63 @@ public class MbmsStreamingManager { * * Multiple calls replace the list of serviceClasses of interest. * - * May throw an IllegalArgumentException or RemoteException. - * - * Synchronous responses include - * <li>SUCCESS</li> - * <li>ERROR_MSDC_CONCURRENT_SERVICE_LIMIT_REACHED</li> + * This may throw an {@link MbmsException} containing one of the following errors: + * {@link MbmsException#ERROR_MIDDLEWARE_NOT_BOUND} + * {@link MbmsException#ERROR_UNKNOWN_REMOTE_EXCEPTION} + * {@link MbmsException#ERROR_CONCURRENT_SERVICE_LIMIT_REACHED} * - * Asynchronous errors through the listener include any of the errors except - * <li>ERROR_MSDC_UNABLE_TO_)START_SERVICE</li> - * <li>ERROR_MSDC_INVALID_SERVICE_ID</li> - * <li>ERROR_MSDC_END_OF_SESSION</li> + * Asynchronous error codes via the {@link MbmsStreamingManagerCallback#error(int, String)} + * callback can include any of the errors except: + * {@link MbmsException#ERROR_UNABLE_TO_START_SERVICE} + * {@link MbmsException#ERROR_END_OF_SESSION} */ - public int getStreamingServices(List<String> classList) { - return 0; + public void getStreamingServices(List<String> classList) throws MbmsException { + if (mService == null) { + throw new MbmsException(MbmsException.ERROR_MIDDLEWARE_NOT_BOUND); + } + try { + int returnCode = mService.getStreamingServices(mAppName, mSubscriptionId, classList); + if (returnCode != MbmsException.SUCCESS) { + throw new MbmsException(returnCode); + } + } catch (RemoteException e) { + throw new MbmsException(MbmsException.ERROR_UNKNOWN_REMOTE_EXCEPTION); + } } /** * Starts streaming a requested service, reporting status to the indicated listener. - * Returns an object used to control that stream. + * Returns an object used to control that stream. The stream may not be ready for consumption + * immediately upon return from this method -- wait until the streaming state has been + * reported via {@link android.telephony.mbms.StreamingServiceCallback#streamStateChanged(int)}. + * + * May throw an {@link MbmsException} containing any of the following error codes: + * {@link MbmsException#ERROR_MIDDLEWARE_NOT_BOUND} + * {@link MbmsException#ERROR_UNKNOWN_REMOTE_EXCEPTION} + * {@link MbmsException#ERROR_CONCURRENT_SERVICE_LIMIT_REACHED} * - * May throw an IllegalArgumentException or RemoteException. + * May also throw an {@link IllegalArgumentException} or an {@link IllegalStateException} * * Asynchronous errors through the listener include any of the errors */ public StreamingService startStreaming(StreamingServiceInfo serviceInfo, - IStreamingServiceCallback listener) { - return null; - } + StreamingServiceCallback listener) throws MbmsException { + if (mService == null) { + throw new MbmsException(MbmsException.ERROR_MIDDLEWARE_NOT_BOUND); + } - /** - * Lists all the services currently being streamed to the device by this application - * on this given subId. Results are returned asynchronously through the previously - * registered callback. - * - * May throw a RemoteException. - * - * The return value is a success/error-code with the following possible values: - * <li>SUCCESS</li> - * <li>ERROR_MSDC_CONCURRENT_SERVICE_LIMIT_REACHED</li> - * - * Asynchronous errors through the listener include any of the errors except - * <li>ERROR_UNABLED_TO_START_SERVICE</li> - * <li>ERROR_MSDC_INVALID_SERVICE_ID</li> - * <li>ERROR_MSDC_END_OF_SESSION</li> - * - */ - public int getActiveStreamingServices() { - return 0; + try { + int returnCode = mService.startStreaming( + mAppName, mSubscriptionId, serviceInfo.getServiceId(), listener); + if (returnCode != MbmsException.SUCCESS) { + throw new MbmsException(returnCode); + } + } catch (RemoteException e) { + throw new MbmsException(MbmsException.ERROR_UNKNOWN_REMOTE_EXCEPTION); + } + + return new StreamingService( + mAppName, mSubscriptionId, mService, serviceInfo, listener); } private void bindAndInitialize() throws MbmsException { @@ -262,7 +269,7 @@ public class MbmsStreamingManager { } catch (RemoteException e) { mService = null; Log.e(LOG_TAG, "Service died before initialization"); - throw new MbmsException(MbmsException.ERROR_INITIALIZATION_REMOTE_EXCEPTION); + throw new MbmsException(MbmsException.ERROR_UNKNOWN_REMOTE_EXCEPTION); } } } diff --git a/telephony/java/android/telephony/NetworkScan.java b/telephony/java/android/telephony/NetworkScan.java new file mode 100644 index 000000000000..0cb4cff0858e --- /dev/null +++ b/telephony/java/android/telephony/NetworkScan.java @@ -0,0 +1,83 @@ +/* + * 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.telephony; + +import android.content.Context; +import android.os.RemoteException; +import android.os.ServiceManager; +import android.util.Log; + +import com.android.internal.telephony.ITelephony; + +/** + * Allows applications to request the system to perform a network scan. + * + * The caller of {@link #requestNetworkScan(NetworkScanRequest, NetworkScanCallback)} will + * receive a NetworkScan which contains the callback method to stop the scan requested. + * @hide + */ +public class NetworkScan { + + public static final String TAG = "NetworkScan"; + + public static final int SUCCESS = 0; + public static final int ERROR_INVALID_SCAN = 1; + public static final int ERROR_UNSUPPORTED = 2; + public static final int ERROR_INTERRUPTED = 3; + public static final int ERROR_CANCELLED = 4; + + private final int mScanId; + private final int mSubId; + + /** + * Stops the network scan + * + * This is the callback method to stop an ongoing scan. When user requests a new scan, + * a NetworkScan object will be returned, and the user can stop the scan by calling this + * method. + */ + public void stop() throws RemoteException { + try { + ITelephony telephony = getITelephony(); + if (telephony != null) { + telephony.stopNetworkScan(mSubId, mScanId); + } else { + throw new RemoteException("Failed to get the ITelephony instance."); + } + } catch (RemoteException ex) { + Rlog.e(TAG, "stopNetworkScan RemoteException", ex); + throw new RemoteException("Failed to stop the network scan with id " + mScanId); + } + } + + /** + * Creates a new NetworkScan with scanId + * + * @param scanId The id of the scan + * @param subId the id of the subscription + * @hide + */ + public NetworkScan(int scanId, int subId) { + mScanId = scanId; + mSubId = subId; + } + + private ITelephony getITelephony() { + return ITelephony.Stub.asInterface( + ServiceManager.getService(Context.TELEPHONY_SERVICE)); + } +} diff --git a/telephony/java/android/telephony/NetworkScanRequest.aidl b/telephony/java/android/telephony/NetworkScanRequest.aidl new file mode 100644 index 000000000000..5addb1cd7c59 --- /dev/null +++ b/telephony/java/android/telephony/NetworkScanRequest.aidl @@ -0,0 +1,19 @@ +/* + * 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.telephony; + +parcelable NetworkScanRequest; diff --git a/telephony/java/android/telephony/NetworkScanRequest.java b/telephony/java/android/telephony/NetworkScanRequest.java new file mode 100644 index 000000000000..0a542a7aacef --- /dev/null +++ b/telephony/java/android/telephony/NetworkScanRequest.java @@ -0,0 +1,115 @@ +/* + * 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.telephony; + +import android.os.Parcel; +import android.os.Parcelable; + +import java.util.Arrays; + +/** + * Defines a request to peform a network scan. + * + * This class defines whether the network scan will be performed only once or periodically until + * cancelled, when the scan is performed periodically, the time interval is not controlled by the + * user but defined by the modem vendor. + * @hide + */ +public final class NetworkScanRequest implements Parcelable { + + /** Performs the scan only once */ + public static final int SCAN_TYPE_ONE_SHOT = 0; + /** + * Performs the scan periodically until cancelled + * + * The modem will start new scans periodically, and the interval between two scans is usually + * multiple minutes. + * */ + public static final int SCAN_TYPE_PERIODIC = 1; + + /** Defines the type of the scan. */ + public int scanType; + + /** Describes the radio access technologies with bands or channels that need to be scanned. */ + public RadioAccessSpecifier[] specifiers; + + /** + * Creates a new NetworkScanRequest with scanType and network specifiers + * + * @param scanType The type of the scan + * @param specifiers the radio network with bands / channels to be scanned + */ + public NetworkScanRequest(int scanType, RadioAccessSpecifier[] specifiers) { + this.scanType = scanType; + this.specifiers = specifiers; + } + + @Override + public int describeContents() { + return 0; + } + + @Override + public void writeToParcel(Parcel dest, int flags) { + dest.writeInt(scanType); + dest.writeParcelableArray(specifiers, flags); + } + + private NetworkScanRequest(Parcel in) { + scanType = in.readInt(); + specifiers = (RadioAccessSpecifier[]) in.readParcelableArray( + Object.class.getClassLoader(), + RadioAccessSpecifier.class); + } + + @Override + public boolean equals (Object o) { + NetworkScanRequest nsr; + + try { + nsr = (NetworkScanRequest) o; + } catch (ClassCastException ex) { + return false; + } + + if (o == null) { + return false; + } + + return (scanType == nsr.scanType + && Arrays.equals(specifiers, nsr.specifiers)); + } + + @Override + public int hashCode () { + return ((scanType * 31) + + (Arrays.hashCode(specifiers)) * 37); + } + + public static final Creator<NetworkScanRequest> CREATOR = + new Creator<NetworkScanRequest>() { + @Override + public NetworkScanRequest createFromParcel(Parcel in) { + return new NetworkScanRequest(in); + } + + @Override + public NetworkScanRequest[] newArray(int size) { + return new NetworkScanRequest[size]; + } + }; +} diff --git a/telephony/java/android/telephony/RadioAccessSpecifier.aidl b/telephony/java/android/telephony/RadioAccessSpecifier.aidl new file mode 100644 index 000000000000..7e09e0b4f74c --- /dev/null +++ b/telephony/java/android/telephony/RadioAccessSpecifier.aidl @@ -0,0 +1,19 @@ +/* + * 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.telephony; + +parcelable RadioAccessSpecifier; diff --git a/telephony/java/android/telephony/RadioAccessSpecifier.java b/telephony/java/android/telephony/RadioAccessSpecifier.java new file mode 100644 index 000000000000..33ce8b4212bc --- /dev/null +++ b/telephony/java/android/telephony/RadioAccessSpecifier.java @@ -0,0 +1,129 @@ +/* + * 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.telephony; + +import android.os.Parcel; +import android.os.Parcelable; + +import java.util.Arrays; + +/** + * Describes a particular radio access network to be scanned. + * + * The scan can be performed on either bands or channels for a specific radio access network type. + * @hide + */ +public final class RadioAccessSpecifier implements Parcelable { + + /** + * The radio access network that needs to be scanned + * + * See {@link RadioNetworkConstants.RadioAccessNetworks} for details. + */ + public int radioAccessNetwork; + + /** + * The frequency bands that need to be scanned + * + * bands must be used together with radioAccessNetwork + * + * See {@link RadioNetworkConstants} for details. + */ + public int[] bands; + + /** + * The frequency channels that need to be scanned + * + * channels must be used together with radioAccessNetwork + * + * See {@link RadioNetworkConstants.RadioAccessNetworks} for details. + */ + public int[] channels; + + /** + * Creates a new RadioAccessSpecifier with radio network, bands and channels + * + * The user must specify the radio network type, and at least specify either of frequency + * bands or channels. + * + * @param ran The type of the radio access network + * @param bands the frequency bands to be scanned + * @param channels the frequency bands to be scanned + */ + public RadioAccessSpecifier(int ran, int[] bands, int[] channels) { + this.radioAccessNetwork = ran; + this.bands = bands; + this.channels = channels; + } + + public static final Parcelable.Creator<RadioAccessSpecifier> CREATOR = + new Parcelable.Creator<RadioAccessSpecifier> (){ + @Override + public RadioAccessSpecifier createFromParcel(Parcel in) { + return new RadioAccessSpecifier(in); + } + + @Override + public RadioAccessSpecifier[] newArray(int size) { + return new RadioAccessSpecifier[size]; + } + }; + + @Override + public int describeContents() { + return 0; + } + + @Override + public void writeToParcel(Parcel dest, int flags) { + dest.writeInt(radioAccessNetwork); + dest.writeIntArray(bands); + dest.writeIntArray(channels); + } + + private RadioAccessSpecifier(Parcel in) { + radioAccessNetwork = in.readInt(); + bands = in.createIntArray(); + channels = in.createIntArray(); + } + + @Override + public boolean equals (Object o) { + RadioAccessSpecifier ras; + + try { + ras = (RadioAccessSpecifier) o; + } catch (ClassCastException ex) { + return false; + } + + if (o == null) { + return false; + } + + return (radioAccessNetwork == ras.radioAccessNetwork + && Arrays.equals(bands, ras.bands) + && Arrays.equals(channels, ras.channels)); + } + + @Override + public int hashCode () { + return ((radioAccessNetwork * 31) + + (Arrays.hashCode(bands) * 37) + + (Arrays.hashCode(channels)) * 39); + } +} diff --git a/telephony/java/android/telephony/RadioNetworkConstants.java b/telephony/java/android/telephony/RadioNetworkConstants.java new file mode 100644 index 000000000000..1a9072d3eb0a --- /dev/null +++ b/telephony/java/android/telephony/RadioNetworkConstants.java @@ -0,0 +1,169 @@ +/* + * 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.telephony; + +/** + * Contains radio access network related constants. + * @hide + */ +public final class RadioNetworkConstants { + + public static final class RadioAccessNetworks { + public static final int GERAN = 1; + public static final int UTRAN = 2; + public static final int EUTRAN = 3; + /** @hide */ + public static final int CDMA2000 = 4; + } + + /** + * Frenquency bands for GERAN. + * http://www.etsi.org/deliver/etsi_ts/145000_145099/145005/14.00.00_60/ts_145005v140000p.pdf + */ + public static final class GeranBands { + public static final int BAND_T380 = 1; + public static final int BAND_T410 = 2; + public static final int BAND_450 = 3; + public static final int BAND_480 = 4; + public static final int BAND_710 = 5; + public static final int BAND_750 = 6; + public static final int BAND_T810 = 7; + public static final int BAND_850 = 8; + public static final int BAND_P900 = 9; + public static final int BAND_E900 = 10; + public static final int BAND_R900 = 11; + public static final int BAND_DCS1800 = 12; + public static final int BAND_PCS1900 = 13; + public static final int BAND_ER900 = 14; + } + + /** + * Frenquency bands for UTRAN. + * http://www.etsi.org/deliver/etsi_ts/125100_125199/125104/13.03.00_60/ts_125104v130p.pdf + */ + public static final class UtranBands { + public static final int BAND_1 = 1; + public static final int BAND_2 = 2; + public static final int BAND_3 = 3; + public static final int BAND_4 = 4; + public static final int BAND_5 = 5; + public static final int BAND_6 = 6; + public static final int BAND_7 = 7; + public static final int BAND_8 = 8; + public static final int BAND_9 = 9; + public static final int BAND_10 = 10; + public static final int BAND_11 = 11; + public static final int BAND_12 = 12; + public static final int BAND_13 = 13; + public static final int BAND_14 = 14; + /** band 15, 16, 17, 18 are reserved */ + public static final int BAND_19 = 19; + public static final int BAND_20 = 20; + public static final int BAND_21 = 21; + public static final int BAND_22 = 22; + /** band 23, 24 are reserved */ + public static final int BAND_25 = 25; + public static final int BAND_26 = 26; + } + + /** + * Frenquency bands for EUTRAN. + * http://www.etsi.org/deliver/etsi_ts/136100_136199/136101/14.03.00_60/ts_136101v140p.pdf + */ + public static final class EutranBands { + public static final int BAND_1 = 1; + public static final int BAND_2 = 2; + public static final int BAND_3 = 3; + public static final int BAND_4 = 4; + public static final int BAND_5 = 5; + public static final int BAND_6 = 6; + public static final int BAND_7 = 7; + public static final int BAND_8 = 8; + public static final int BAND_9 = 9; + public static final int BAND_10 = 10; + public static final int BAND_11 = 11; + public static final int BAND_12 = 12; + public static final int BAND_13 = 13; + public static final int BAND_14 = 14; + public static final int BAND_17 = 17; + public static final int BAND_18 = 18; + public static final int BAND_19 = 19; + public static final int BAND_20 = 20; + public static final int BAND_21 = 21; + public static final int BAND_22 = 22; + public static final int BAND_23 = 23; + public static final int BAND_24 = 24; + public static final int BAND_25 = 25; + public static final int BAND_26 = 26; + public static final int BAND_27 = 27; + public static final int BAND_28 = 28; + public static final int BAND_30 = 30; + public static final int BAND_31 = 31; + public static final int BAND_33 = 33; + public static final int BAND_34 = 34; + public static final int BAND_35 = 35; + public static final int BAND_36 = 36; + public static final int BAND_37 = 37; + public static final int BAND_38 = 38; + public static final int BAND_39 = 39; + public static final int BAND_40 = 40; + public static final int BAND_41 = 41; + public static final int BAND_42 = 42; + public static final int BAND_43 = 43; + public static final int BAND_44 = 44; + public static final int BAND_45 = 45; + public static final int BAND_46 = 46; + public static final int BAND_47 = 47; + public static final int BAND_48 = 48; + public static final int BAND_65 = 65; + public static final int BAND_66 = 66; + public static final int BAND_68 = 68; + public static final int BAND_70 = 70; + } + + /** + * Frenquency bands for CDMA2000. + * http://www.3gpp2.org/Public_html/Specs/C.S0057-E_v1.0_Bandclass_Specification.pdf + * @hide + * + * TODO(yinxu): Check with the nexus team about the definition of CDMA bands. + */ + public static final class CdmaBands { + public static final int BAND_0 = 1; + public static final int BAND_1 = 2; + public static final int BAND_2 = 3; + public static final int BAND_3 = 4; + public static final int BAND_4 = 5; + public static final int BAND_5 = 6; + public static final int BAND_6 = 7; + public static final int BAND_7 = 8; + public static final int BAND_8 = 9; + public static final int BAND_9 = 10; + public static final int BAND_10 = 11; + public static final int BAND_11 = 12; + public static final int BAND_12 = 13; + public static final int BAND_13 = 14; + public static final int BAND_14 = 15; + public static final int BAND_15 = 16; + public static final int BAND_16 = 17; + public static final int BAND_17 = 18; + public static final int BAND_18 = 19; + public static final int BAND_19 = 20; + public static final int BAND_20 = 21; + public static final int BAND_21 = 22; + } +} diff --git a/telephony/java/android/telephony/SmsMessage.java b/telephony/java/android/telephony/SmsMessage.java index d6e74cf5ede9..dcdda8685e02 100644 --- a/telephony/java/android/telephony/SmsMessage.java +++ b/telephony/java/android/telephony/SmsMessage.java @@ -463,9 +463,28 @@ public class SmsMessage { */ public static SubmitPdu getSubmitPdu(String scAddress, String destinationAddress, String message, boolean statusReportRequested) { - SubmitPduBase spb; + return getSubmitPdu(scAddress, destinationAddress, message, statusReportRequested, + SubscriptionManager.getDefaultSmsSubscriptionId()); + } - if (useCdmaFormatForMoSms()) { + /** + * Get an SMS-SUBMIT PDU for a destination address and a message. + * This method will not attempt to use any GSM national language 7 bit encodings. + * + * @param scAddress Service Centre address. Null means use default. + * @param destinationAddress the address of the destination for the message. + * @param message String representation of the message payload. + * @param statusReportRequested Indicates whether a report is requested for this message. + * @param subId Subscription of the message + * @return a <code>SubmitPdu</code> containing the encoded SC + * address, if applicable, and the encoded message. + * Returns null on encode error. + * @hide + */ + public static SubmitPdu getSubmitPdu(String scAddress, + String destinationAddress, String message, boolean statusReportRequested, int subId) { + SubmitPduBase spb; + if (useCdmaFormatForMoSms(subId)) { spb = com.android.internal.telephony.cdma.SmsMessage.getSubmitPdu(scAddress, destinationAddress, message, statusReportRequested, null); } else { @@ -758,12 +777,27 @@ public class SmsMessage { * @return true if Cdma format should be used for MO SMS, false otherwise. */ private static boolean useCdmaFormatForMoSms() { - if (!SmsManager.getDefault().isImsSmsSupported()) { + // IMS is registered with SMS support, check the SMS format supported + return useCdmaFormatForMoSms(SubscriptionManager.getDefaultSmsSubscriptionId()); + } + + /** + * Determines whether or not to use CDMA format for MO SMS. + * If SMS over IMS is supported, then format is based on IMS SMS format, + * otherwise format is based on current phone type. + * + * @param subId Subscription for which phone type is returned. + * + * @return true if Cdma format should be used for MO SMS, false otherwise. + */ + private static boolean useCdmaFormatForMoSms(int subId) { + SmsManager smsManager = SmsManager.getSmsManagerForSubscriptionId(subId); + if (!smsManager.isImsSmsSupported()) { // use Voice technology to determine SMS format. - return isCdmaVoice(); + return isCdmaVoice(subId); } // IMS is registered with SMS support, check the SMS format supported - return (SmsConstants.FORMAT_3GPP2.equals(SmsManager.getDefault().getImsSmsFormat())); + return (SmsConstants.FORMAT_3GPP2.equals(smsManager.getImsSmsFormat())); } /** @@ -772,10 +806,18 @@ public class SmsMessage { * @return true if current phone type is cdma, false otherwise. */ private static boolean isCdmaVoice() { - int activePhone = TelephonyManager.getDefault().getCurrentPhoneType(); - return (PHONE_TYPE_CDMA == activePhone); + return isCdmaVoice(SubscriptionManager.getDefaultSmsSubscriptionId()); } + /** + * Determines whether or not to current phone type is cdma + * + * @return true if current phone type is cdma, false otherwise. + */ + private static boolean isCdmaVoice(int subId) { + int activePhone = TelephonyManager.getDefault().getCurrentPhoneType(subId); + return (PHONE_TYPE_CDMA == activePhone); + } /** * Decide if the carrier supports long SMS. * {@hide} diff --git a/telephony/java/android/telephony/TelephonyManager.java b/telephony/java/android/telephony/TelephonyManager.java index 32536fc77343..3fcb2806bad4 100644 --- a/telephony/java/android/telephony/TelephonyManager.java +++ b/telephony/java/android/telephony/TelephonyManager.java @@ -39,6 +39,11 @@ import android.provider.Settings; import android.provider.Settings.SettingNotFoundException; import android.os.Bundle; import android.os.Handler; +import android.os.HandlerThread; +import android.os.Looper; +import android.os.Message; +import android.os.Messenger; +import android.os.Parcelable; import android.os.PersistableBundle; import android.os.RemoteException; import android.os.ResultReceiver; @@ -144,6 +149,7 @@ public class TelephonyManager { private final Context mContext; private final int mSubId; private SubscriptionManager mSubscriptionManager; + private TelephonyScanManager mTelephonyScanManager; private static String multiSimConfig = SystemProperties.get(TelephonyProperties.PROPERTY_MULTI_SIM_CONFIG); @@ -4573,6 +4579,32 @@ public class TelephonyManager { } /** + * Request a network scan. + * + * This method is asynchronous, so the network scan results will be returned by callback. + * The returned NetworkScan will contain a callback method which can be used to stop the scan. + * + * <p> + * Requires Permission: + * {@link android.Manifest.permission#MODIFY_PHONE_STATE MODIFY_PHONE_STATE} + * Or the calling app has carrier privileges. @see #hasCarrierPrivileges + * + * @param request Contains all the RAT with bands/channels that need to be scanned. + * @param callback Returns network scan results or errors. + * @return A NetworkScan obj which contains a callback which can stop the scan. + * @hide + */ + public NetworkScan requestNetworkScan( + NetworkScanRequest request, TelephonyScanManager.NetworkScanCallback callback) { + synchronized (this) { + if (mTelephonyScanManager == null) { + mTelephonyScanManager = new TelephonyScanManager(); + } + } + return mTelephonyScanManager.requestNetworkScan(getSubId(), request, callback); + } + + /** * Ask the radio to connect to the input network and change selection mode to manual. * * <p> @@ -5696,35 +5728,75 @@ public class TelephonyManager { } /** - * Set SIM card power state. Request is equivalent to inserting or removing the card. + * Requested state of SIM + * + * CARD_POWER_DOWN + * Powers down the SIM. SIM must be up prior. * - * @param powerUp True if powering up the SIM, otherwise powering down + * CARD_POWER_UP + * Powers up the SIM normally. SIM must be down prior. + * + * CARD_POWER_UP_PASS_THROUGH + * Powers up the SIM in PASS_THROUGH mode. SIM must be down prior. + * When SIM is powered up in PASS_THOUGH mode, the modem does not send + * any command to it (for example SELECT of MF, or TERMINAL CAPABILITY), + * and the SIM card is controlled completely by Telephony sending APDUs + * directly. The SIM card state will be RIL_CARDSTATE_PRESENT and the + * number of card apps will be 0. + * No new error code is generated. Emergency calls are supported in the + * same way as if the SIM card is absent. + * The PASS_THROUGH mode is valid only for the specific card session where it + * is activated, and normal behavior occurs at the next SIM initialization, + * unless PASS_THROUGH mode is requested again. Hence, the last power-up mode + * is NOT persistent across boots. On reboot, SIM will power up normally. + */ + /** @hide */ + public static final int CARD_POWER_DOWN = 0; + /** @hide */ + public static final int CARD_POWER_UP = 1; + /** @hide */ + public static final int CARD_POWER_UP_PASS_THROUGH = 2; + + /** + * Set SIM card power state. + * + * @param state State of SIM (power down, power up, pass through) + * @see #CARD_POWER_DOWN + * @see #CARD_POWER_UP + * @see #CARD_POWER_UP_PASS_THROUGH + * Callers should monitor for {@link TelephonyIntents#ACTION_SIM_STATE_CHANGED} + * broadcasts to determine success or failure and timeout if needed. * * <p>Requires Permission: * {@link android.Manifest.permission#MODIFY_PHONE_STATE MODIFY_PHONE_STATE} * * @hide **/ - public void setSimPowerState(boolean powerUp) { - setSimPowerStateForSlot(getSlotIndex(), powerUp); + public void setSimPowerState(int state) { + setSimPowerStateForSlot(getSlotIndex(), state); } /** - * Set SIM card power state. Request is equivalent to inserting or removing the card. + * Set SIM card power state. * * @param slotIndex SIM slot id - * @param powerUp True if powering up the SIM, otherwise powering down + * @param state State of SIM (power down, power up, pass through) + * @see #CARD_POWER_DOWN + * @see #CARD_POWER_UP + * @see #CARD_POWER_UP_PASS_THROUGH + * Callers should monitor for {@link TelephonyIntents#ACTION_SIM_STATE_CHANGED} + * broadcasts to determine success or failure and timeout if needed. * * <p>Requires Permission: * {@link android.Manifest.permission#MODIFY_PHONE_STATE MODIFY_PHONE_STATE} * * @hide **/ - public void setSimPowerStateForSlot(int slotIndex, boolean powerUp) { + public void setSimPowerStateForSlot(int slotIndex, int state) { try { ITelephony telephony = getITelephony(); if (telephony != null) { - telephony.setSimPowerStateForSlot(slotIndex, powerUp); + telephony.setSimPowerStateForSlot(slotIndex, state); } } catch (RemoteException e) { Log.e(TAG, "Error calling ITelephony#setSimPowerStateForSlot", e); @@ -6442,5 +6514,26 @@ public class TelephonyManager { } return false; } + + /** + * Get the most recently available signal strength information. + * + * Get the most recent SignalStrength information reported by the modem. Due + * to power saving this information may not always be current. + * @return the most recent cached signal strength info from the modem + * @hide + */ + @Nullable + public SignalStrength getSignalStrength() { + try { + ITelephony service = getITelephony(); + if (service != null) { + return service.getSignalStrength(getSubId()); + } + } catch (RemoteException e) { + Log.e(TAG, "Error calling ITelephony#getSignalStrength", e); + } + return null; + } } diff --git a/telephony/java/android/telephony/TelephonyScanManager.java b/telephony/java/android/telephony/TelephonyScanManager.java new file mode 100644 index 000000000000..c905d3a433f3 --- /dev/null +++ b/telephony/java/android/telephony/TelephonyScanManager.java @@ -0,0 +1,186 @@ +/* + * 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.telephony; + +import static com.android.internal.util.Preconditions.checkNotNull; + +import android.content.Context; +import android.os.Binder; +import android.os.Handler; +import android.os.HandlerThread; +import android.os.Looper; +import android.os.Message; +import android.os.Messenger; +import android.os.RemoteException; +import android.os.ServiceManager; +import android.util.Log; +import android.util.SparseArray; +import java.util.List; + +import com.android.internal.telephony.ITelephony; + +/** + * Manages the radio access network scan requests and callbacks. + * @hide + */ +public final class TelephonyScanManager { + + private static final String TAG = "TelephonyScanManager"; + + /** @hide */ + public static final int CALLBACK_SCAN_RESULTS = 1; + /** @hide */ + public static final int CALLBACK_SCAN_ERROR = 2; + /** @hide */ + public static final int CALLBACK_SCAN_COMPLETE = 3; + + /** + * The caller of {@link #requestNetworkScan(NetworkScanRequest, NetworkScanCallback)} should + * implement and provide this callback so that the scan results or errors can be returned. + */ + public static abstract class NetworkScanCallback { + /** Returns the scan results to the user, this callback will be called multiple times. */ + public void onResults(List<CellInfo> results) {} + + /** + * Informs the user that the scan has stopped. + * + * This callback will be called when the scan is finished or cancelled by the user. + * The related NetworkScanRequest will be deleted after this callback. + */ + public void onComplete() {} + + /** + * Informs the user that there is some error about the scan. + * + * This callback will be called whenever there is any error about the scan, but the scan + * won't stop unless the onComplete() callback is called. + */ + public void onError(int error) {} + } + + private static class NetworkScanInfo { + private final NetworkScanRequest mRequest; + private final NetworkScanCallback mCallback; + + NetworkScanInfo(NetworkScanRequest request, NetworkScanCallback callback) { + mRequest = request; + mCallback = callback; + } + } + + private final Looper mLooper; + private final Messenger mMessenger; + private SparseArray<NetworkScanInfo> mScanInfo = new SparseArray<NetworkScanInfo>(); + + public TelephonyScanManager() { + HandlerThread thread = new HandlerThread(TAG); + thread.start(); + mLooper = thread.getLooper(); + mMessenger = new Messenger(new Handler(mLooper) { + @Override + public void handleMessage(Message message) { + checkNotNull(message, "message cannot be null"); + NetworkScanInfo nsi; + synchronized (mScanInfo) { + nsi = mScanInfo.get(message.arg2); + } + if (nsi == null) { + throw new RuntimeException( + "Failed to find NetworkScanInfo with id " + message.arg2); + } + NetworkScanCallback callback = nsi.mCallback; + if (callback == null) { + throw new RuntimeException( + "Failed to find NetworkScanCallback with id " + message.arg2); + } + + switch (message.what) { + case CALLBACK_SCAN_RESULTS: + try { + callback.onResults((List<CellInfo>) message.obj); + } catch (Exception e) { + Rlog.e(TAG, "Exception in networkscan callback onResults", e); + } + break; + case CALLBACK_SCAN_ERROR: + try { + callback.onError(message.arg1); + } catch (Exception e) { + Rlog.e(TAG, "Exception in networkscan callback onError", e); + } + break; + case CALLBACK_SCAN_COMPLETE: + try { + callback.onComplete(); + mScanInfo.remove(message.arg2); + } catch (Exception e) { + Rlog.e(TAG, "Exception in networkscan callback onComplete", e); + } + break; + default: + Rlog.e(TAG, "Unhandled message " + Integer.toHexString(message.what)); + break; + } + } + }); + } + + /** + * Request a network scan. + * + * This method is asynchronous, so the network scan results will be returned by callback. + * The returned NetworkScan will contain a callback method which can be used to stop the scan. + * + * <p> + * Requires Permission: + * {@link android.Manifest.permission#MODIFY_PHONE_STATE MODIFY_PHONE_STATE} + * Or the calling app has carrier privileges. @see #hasCarrierPrivileges + * + * @param request Contains all the RAT with bands/channels that need to be scanned. + * @param callback Returns network scan results or errors. + * @return A NetworkScan obj which contains a callback which can stop the scan. + * @hide + */ + public NetworkScan requestNetworkScan(int subId, + NetworkScanRequest request, NetworkScanCallback callback) { + try { + ITelephony telephony = getITelephony(); + if (telephony != null) { + int scanId = telephony.requestNetworkScan(subId, request, mMessenger, new Binder()); + saveScanInfo(scanId, request, callback); + return new NetworkScan(scanId, subId); + } + } catch (RemoteException ex) { + Rlog.e(TAG, "requestNetworkScan RemoteException", ex); + } catch (NullPointerException ex) { + Rlog.e(TAG, "requestNetworkScan NPE", ex); + } + return null; + } + + private void saveScanInfo(int id, NetworkScanRequest request, NetworkScanCallback callback) { + synchronized (mScanInfo) { + mScanInfo.put(id, new NetworkScanInfo(request, callback)); + } + } + + private ITelephony getITelephony() { + return ITelephony.Stub.asInterface( + ServiceManager.getService(Context.TELEPHONY_SERVICE)); + } +} diff --git a/telephony/java/android/telephony/ims/ImsService.java b/telephony/java/android/telephony/ims/ImsService.java index f1f683c70735..511ac3833701 100644 --- a/telephony/java/android/telephony/ims/ImsService.java +++ b/telephony/java/android/telephony/ims/ImsService.java @@ -105,10 +105,11 @@ public abstract class ImsService extends ImsServiceBase { } @Override - public void removeImsFeature(int slotId, int feature) throws RemoteException { + public void removeImsFeature(int slotId, int feature, IImsFeatureStatusCallback c) + throws RemoteException { synchronized (mFeatures) { enforceCallingOrSelfPermission(MODIFY_PHONE_STATE, "removeImsFeature"); - onRemoveImsFeatureInternal(slotId, feature); + onRemoveImsFeatureInternal(slotId, feature, c); } } @@ -355,7 +356,7 @@ public abstract class ImsService extends ImsServiceBase { if (f != null) { f.setContext(this); f.setSlotId(slotId); - f.setImsFeatureStatusCallback(c); + f.addImsFeatureStatusCallback(c); featureMap.put(featureType, f); } @@ -368,7 +369,8 @@ public abstract class ImsService extends ImsServiceBase { * defined in {@link ImsFeature}. */ // Be sure to lock on mFeatures before accessing this method - private void onRemoveImsFeatureInternal(int slotId, int featureType) { + private void onRemoveImsFeatureInternal(int slotId, int featureType, + IImsFeatureStatusCallback c) { SparseArray<ImsFeature> featureMap = mFeatures.get(slotId); if (featureMap == null) { return; @@ -379,7 +381,7 @@ public abstract class ImsService extends ImsServiceBase { featureMap.remove(featureType); featureToRemove.notifyFeatureRemoved(slotId); // Remove reference to Binder - featureToRemove.setImsFeatureStatusCallback(null); + featureToRemove.removeImsFeatureStatusCallback(c); } } diff --git a/telephony/java/android/telephony/ims/feature/ImsFeature.java b/telephony/java/android/telephony/ims/feature/ImsFeature.java index 395f1ccc7a29..9d880b7395ef 100644 --- a/telephony/java/android/telephony/ims/feature/ImsFeature.java +++ b/telephony/java/android/telephony/ims/feature/ImsFeature.java @@ -28,7 +28,11 @@ import com.android.ims.internal.IImsFeatureStatusCallback; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.util.ArrayList; +import java.util.Collections; +import java.util.Iterator; import java.util.List; +import java.util.Set; +import java.util.WeakHashMap; /** * Base class for all IMS features that are supported by the framework. @@ -88,7 +92,8 @@ public abstract class ImsFeature { public static final int STATE_READY = 2; private List<INotifyFeatureRemoved> mRemovedListeners = new ArrayList<>(); - private IImsFeatureStatusCallback mStatusCallback; + private final Set<IImsFeatureStatusCallback> mStatusCallbacks = Collections.newSetFromMap( + new WeakHashMap<IImsFeatureStatusCallback, Boolean>()); private @ImsState int mState = STATE_NOT_AVAILABLE; private int mSlotId = SubscriptionManager.INVALID_SIM_SLOT_INDEX; private Context mContext; @@ -136,11 +141,29 @@ public abstract class ImsFeature { } } - // Not final for testing. - public void setImsFeatureStatusCallback(IImsFeatureStatusCallback c) { - mStatusCallback = c; - // If we have just connected, send queued status. - notifyFeatureState(mState); + public void addImsFeatureStatusCallback(IImsFeatureStatusCallback c) { + if (c == null) { + return; + } + try { + // If we have just connected, send queued status. + c.notifyImsFeatureStatus(mState); + // Add the callback if the callback completes successfully without a RemoteException. + synchronized (mStatusCallbacks) { + mStatusCallbacks.add(c); + } + } catch (RemoteException e) { + Log.w(LOG_TAG, "Couldn't notify feature state: " + e.getMessage()); + } + } + + public void removeImsFeatureStatusCallback(IImsFeatureStatusCallback c) { + if (c == null) { + return; + } + synchronized (mStatusCallbacks) { + mStatusCallbacks.remove(c); + } } /** @@ -148,13 +171,18 @@ public abstract class ImsFeature { * @param state */ private void notifyFeatureState(@ImsState int state) { - if (mStatusCallback != null) { - try { - Log.i(LOG_TAG, "notifying ImsFeatureState=" + state); - mStatusCallback.notifyImsFeatureStatus(state); - } catch (RemoteException e) { - mStatusCallback = null; - Log.w(LOG_TAG, "Couldn't notify feature state: " + e.getMessage()); + synchronized (mStatusCallbacks) { + for (Iterator<IImsFeatureStatusCallback> iter = mStatusCallbacks.iterator(); + iter.hasNext(); ) { + IImsFeatureStatusCallback callback = iter.next(); + try { + Log.i(LOG_TAG, "notifying ImsFeatureState=" + state); + callback.notifyImsFeatureStatus(state); + } catch (RemoteException e) { + // remove if the callback is no longer alive. + iter.remove(); + Log.w(LOG_TAG, "Couldn't notify feature state: " + e.getMessage()); + } } } sendImsServiceIntent(state); diff --git a/telephony/java/android/telephony/mbms/IStreamingServiceCallback.aidl b/telephony/java/android/telephony/mbms/IStreamingServiceCallback.aidl index 7b4ecf25ea9c..891edad8c9bf 100755 --- a/telephony/java/android/telephony/mbms/IStreamingServiceCallback.aidl +++ b/telephony/java/android/telephony/mbms/IStreamingServiceCallback.aidl @@ -17,15 +17,13 @@ package android.telephony.mbms; import android.net.Uri; -import android.telephony.SignalStrength; -import android.telephony.mbms.StreamingService; /** * @hide */ oneway interface IStreamingServiceCallback { void error(int errorCode, String message); - void streamStateChanged(in StreamingService service, int state); + void streamStateChanged(int state); void uriUpdated(in Uri uri); - void signalStrengthUpdated(in SignalStrength signalStrength); + void broadcastSignalStrengthUpdated(int signalStrength); } diff --git a/telephony/java/android/telephony/mbms/MbmsException.java b/telephony/java/android/telephony/mbms/MbmsException.java index cc4a02a13717..a0ded9bd565b 100644 --- a/telephony/java/android/telephony/mbms/MbmsException.java +++ b/telephony/java/android/telephony/mbms/MbmsException.java @@ -16,22 +16,25 @@ package android.telephony.mbms; -import android.os.RemoteException; - /** @hide */ -public class MbmsException extends RemoteException { +public class MbmsException extends Exception { public static final int SUCCESS = 0; public static final int ERROR_NO_SERVICE_INSTALLED = 1; public static final int ERROR_MULTIPLE_SERVICES_INSTALLED = 2; public static final int ERROR_BIND_TIMEOUT_OR_FAILURE = 3; - public static final int ERROR_INITIALIZATION_REMOTE_EXCEPTION = 4; + public static final int ERROR_UNKNOWN_REMOTE_EXCEPTION = 4; public static final int ERROR_ALREADY_INITIALIZED = 5; + public static final int ERROR_CONCURRENT_SERVICE_LIMIT_REACHED = 6; + public static final int ERROR_MIDDLEWARE_NOT_BOUND = 7; + public static final int ERROR_UNABLE_TO_START_SERVICE = 8; + public static final int ERROR_STREAM_ALREADY_STARTED = 9; + public static final int ERROR_END_OF_SESSION = 10; private final int mErrorCode; /** @hide * TODO: future systemapi - * */ + */ public MbmsException(int errorCode) { super(); mErrorCode = errorCode; diff --git a/telephony/java/android/telephony/mbms/ServiceInfo.java b/telephony/java/android/telephony/mbms/ServiceInfo.java index cb621c8bbfd0..f167f0ab228e 100644 --- a/telephony/java/android/telephony/mbms/ServiceInfo.java +++ b/telephony/java/android/telephony/mbms/ServiceInfo.java @@ -114,6 +114,7 @@ public class ServiceInfo implements Parcelable { sessionEndTime = (java.util.Date) in.readSerializable(); } + @Override public void writeToParcel(Parcel dest, int flags) { Set<Locale> keySet = names.keySet(); dest.writeInt(keySet.size()); @@ -128,7 +129,33 @@ public class ServiceInfo implements Parcelable { dest.writeSerializable(sessionEndTime); } + @Override public int describeContents() { return 0; } + + public Map<Locale, String> getNames() { + return names; + } + + public String getClassName() { + return className; + } + + public Locale getLocale() { + return locale; + } + + public String getServiceId() { + return serviceId; + } + + public Date getSessionStartTime() { + return sessionStartTime; + } + + public Date getSessionEndTime() { + return sessionEndTime; + } + } diff --git a/telephony/java/android/telephony/mbms/StreamingService.aidl b/telephony/java/android/telephony/mbms/StreamingService.aidl deleted file mode 100755 index 0c286f3a0502..000000000000 --- a/telephony/java/android/telephony/mbms/StreamingService.aidl +++ /dev/null @@ -1,19 +0,0 @@ -/* -** Copyright 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.telephony.mbms; - -parcelable StreamingService; diff --git a/telephony/java/android/telephony/mbms/StreamingService.java b/telephony/java/android/telephony/mbms/StreamingService.java index 8cc604356bad..ac5fbdf62666 100644 --- a/telephony/java/android/telephony/mbms/StreamingService.java +++ b/telephony/java/android/telephony/mbms/StreamingService.java @@ -19,46 +19,60 @@ package android.telephony.mbms; import android.net.Uri; import android.os.Parcel; import android.os.Parcelable; -import android.telephony.SignalStrength; +import android.os.RemoteException; +import android.telephony.mbms.vendor.IMbmsStreamingService; +import android.util.Log; /** * @hide */ public class StreamingService { - + private static final String LOG_TAG = "MbmsStreamingService"; public final static int STATE_STOPPED = 1; public final static int STATE_STARTED = 2; public final static int STATE_STALLED = 3; + private final String mAppName; + private final int mSubscriptionId; + private final IMbmsStreamingService mService; + private final StreamingServiceInfo mServiceInfo; + private final IStreamingServiceCallback mCallback; /** + * @hide */ - StreamingService(StreamingServiceInfo streamingServiceInfo, - IStreamingServiceCallback listener) { + public StreamingService(String appName, + int subscriptionId, + IMbmsStreamingService service, + StreamingServiceInfo streamingServiceInfo, + IStreamingServiceCallback callback) { + mAppName = appName; + mSubscriptionId = subscriptionId; + mService = service; + mServiceInfo = streamingServiceInfo; + mCallback = callback; } /** * Retreive the Uri used to play this stream. * - * This may throw a RemoteException. + * This may throw a {@link MbmsException} with the error code + * {@link MbmsException#ERROR_UNKNOWN_REMOTE_EXCEPTION} + * @return The {@link Uri} to pass to the streaming client. */ - public Uri getPlaybackUri() { - return null; + public Uri getPlaybackUri() throws MbmsException { + try { + return mService.getPlaybackUri(mAppName, mSubscriptionId, mServiceInfo.getServiceId()); + } catch (RemoteException e) { + Log.w(LOG_TAG, "Caught remote exception calling getPlaybackUri: " + e); + throw new MbmsException(MbmsException.ERROR_UNKNOWN_REMOTE_EXCEPTION); + } } /** * Retreive the info for this StreamingService. */ public StreamingServiceInfo getInfo() { - return null; - } - - /** - * Retreive the current state of this stream. - * - * This may throw a RemoteException. - */ - public int getState() { - return STATE_STOPPED; + return mServiceInfo; } /** @@ -69,41 +83,13 @@ public class StreamingService { public void stopStreaming() { } - /** - * Switch this stream to a different service. Used for smooth transitions. - * - * This may throw a RemoteException. - * - * Asynchronous errors through the listener include any of the errors except - * <li>ERROR_MSDC_UNABLE_TO_INITIALIZE</li> - */ - public void switchStream(StreamingServiceInfo streamingServiceInfo) { - } - - public void dispose() { - } - - public static final Parcelable.Creator<StreamingService> CREATOR = - new Parcelable.Creator<StreamingService>() { - @Override - public StreamingService createFromParcel(Parcel in) { - return new StreamingService(in); - } - - @Override - public StreamingService[] newArray(int size) { - return new StreamingService[size]; + public void dispose() throws MbmsException { + try { + mService.disposeStream(mAppName, mSubscriptionId, mServiceInfo.getServiceId()); + } catch (RemoteException e) { + Log.w(LOG_TAG, "Caught remote exception calling disposeStream: " + e); + throw new MbmsException(MbmsException.ERROR_UNKNOWN_REMOTE_EXCEPTION); } - }; - - private StreamingService(Parcel in) { - } - - public void writeToParcel(Parcel dest, int flags) { - } - - public int describeContents() { - return 0; } } diff --git a/telephony/java/android/telephony/mbms/StreamingServiceCallback.java b/telephony/java/android/telephony/mbms/StreamingServiceCallback.java index 7f5c486f8d90..bd0a1b3bd7d9 100644 --- a/telephony/java/android/telephony/mbms/StreamingServiceCallback.java +++ b/telephony/java/android/telephony/mbms/StreamingServiceCallback.java @@ -17,14 +17,21 @@ package android.telephony.mbms; import android.net.Uri; -import android.telephony.SignalStrength; /** - * A Callback class for use when the applicaiton is actively streaming content. + * A Callback class for use when the application is actively streaming content. * @hide */ public class StreamingServiceCallback extends IStreamingServiceCallback.Stub { + /** + * Indicates broadcast signal strength is not available for this service. + * + * This may be due to the service no longer being available due to geography + * or timing (end of service) or because lack of demand has caused the service + * to be delivered via unicast. + */ + public static final int SIGNAL_STRENGTH_UNAVAILABLE = -1; public void error(int errorCode, String message) { // default implementation empty @@ -36,7 +43,7 @@ public class StreamingServiceCallback extends IStreamingServiceCallback.Stub { * See {@link StreamingService#STATE_STOPPED}, {@link StreamingService#STATE_STARTED} * and {@link StreamingService#STATE_STALLED}. */ - public void streamStateChanged(StreamingService service, int state) { + public void streamStateChanged(int state) { // default implementation empty } @@ -51,19 +58,16 @@ public class StreamingServiceCallback extends IStreamingServiceCallback.Stub { } /** - * Signal Strength updated. + * Broadcast Signal Strength updated. * * This signal strength is the BROADCAST signal strength which, * depending on technology in play and it's deployment, may be * stronger or weaker than the traditional UNICAST signal - * strength. - * - * A {@link android.telephony.SignalStrength#getLevel} result of 0 means - * you don't have coverage for this stream, either due to geographic - * restrictions, poor tower coverage or something (yards of concrete?) - * interferring with the signal. + * strength. It a simple int from 0-4 for valid levels or + * {@link #SIGNAL_STRENGTH_UNAVAILABLE} if broadcast is not available + * for this service due to timing, geography or popularity. */ - public void signalStrengthUpdated(SignalStrength signalStrength) { + public void broadcastSignalStrengthUpdated(int signalStrength) { // default implementation empty } } diff --git a/telephony/java/android/telephony/mbms/vendor/IMbmsStreamingService.aidl b/telephony/java/android/telephony/mbms/vendor/IMbmsStreamingService.aidl index ddc661df8c91..8ff7fa7c54f3 100755 --- a/telephony/java/android/telephony/mbms/vendor/IMbmsStreamingService.aidl +++ b/telephony/java/android/telephony/mbms/vendor/IMbmsStreamingService.aidl @@ -19,9 +19,7 @@ package android.telephony.mbms.vendor; import android.net.Uri; import android.telephony.mbms.IMbmsStreamingManagerCallback; import android.telephony.mbms.IStreamingServiceCallback; -import android.telephony.mbms.StreamingService; import android.telephony.mbms.StreamingServiceInfo; -import android.telephony.SignalStrength; /** * The interface the opaque MbmsStreamingService will satisfy. @@ -29,55 +27,23 @@ import android.telephony.SignalStrength; */ interface IMbmsStreamingService { - /** - * Initialize streaming service - * Registers this listener, subId with this appName - * - */ int initialize(IMbmsStreamingManagerCallback listener, String appName, int subId); - - /** - * - Registers serviceClasses of interest with the uid/appName/subId key. - * - Starts asynch fetching data on streaming services of matching classes to be reported - * later by callback. - * - * Note that subsequent calls with the same callback, appName, subId and uid will replace - * the service class list. - */ int getStreamingServices(String appName, int subId, in List<String> serviceClasses); - /** - * - Starts streaming the serviceId given. - * - if the uid/appName/subId don't match a previously registered callback an error will - * be returned - * - Streaming status will be sent via the included listener, including an initial - * URL-change and State-change pair. - */ int startStreaming(String appName, int subId, String serviceId, IStreamingServiceCallback listener); /** - * Asynchronously fetches all Services being streamed by this uid/appName/subId. - */ - int getActiveStreamingServices(String appName, int subId); - - - /** * Per-stream api. Note each specifies what stream they apply to. */ Uri getPlaybackUri(String appName, int subId, String serviceId); - void switchStreams(String appName, int subId, String oldServiceId, String newServiceId); - - int getState(String appName, int subId, String serviceId); - void stopStreaming(String appName, int subId, String serviceId); void disposeStream(String appName, int subId, String serviceId); - /** * End of life for all MbmsStreamingManager's created by this uid/appName/subId. * Ends any streams run under this uid/appname/subId and calls the disposed methods diff --git a/telephony/java/android/telephony/mbms/vendor/MbmsStreamingServiceBase.java b/telephony/java/android/telephony/mbms/vendor/MbmsStreamingServiceBase.java index 9f0c0e94d66b..37f47ffb52f2 100644 --- a/telephony/java/android/telephony/mbms/vendor/MbmsStreamingServiceBase.java +++ b/telephony/java/android/telephony/mbms/vendor/MbmsStreamingServiceBase.java @@ -16,11 +16,12 @@ package android.telephony.mbms.vendor; +import android.annotation.Nullable; import android.net.Uri; import android.os.RemoteException; import android.telephony.mbms.IMbmsStreamingManagerCallback; import android.telephony.mbms.IStreamingServiceCallback; -import android.telephony.mbms.StreamingService; +import android.telephony.mbms.MbmsException; import java.util.List; @@ -29,43 +30,81 @@ import java.util.List; * TODO: future systemapi */ public class MbmsStreamingServiceBase extends IMbmsStreamingService.Stub { - + /** + * Initialize streaming service for this app and subId, registering the listener. + * + * May throw an {@link IllegalArgumentException} or a {@link SecurityException} + * + * @param listener The callback to use to communicate with the app. + * @param appName The app name as negotiated with the wireless carrier. + * @param subscriptionId The subscription ID to use. + * @return {@link MbmsException#SUCCESS} or {@link MbmsException#ERROR_ALREADY_INITIALIZED} + */ @Override - public int initialize(IMbmsStreamingManagerCallback listener, String appName, int subId) - throws RemoteException { + public int initialize(IMbmsStreamingManagerCallback listener, String appName, + int subscriptionId) throws RemoteException { return 0; } + /** + * Registers serviceClasses of interest with the appName/subId key. + * Starts async fetching data on streaming services of matching classes to be reported + * later via {@link IMbmsStreamingManagerCallback#streamingServicesUpdated(List)} + * + * Note that subsequent calls with the same uid, appName and subId will replace + * the service class list. + * + * May throw an {@link IllegalArgumentException} or an {@link IllegalStateException} + * + * @param appName The app name as negotiated with the wireless carrier. + * @param subscriptionId The subscription id to use. + * @param serviceClasses The service classes that the app wishes to get info on. The strings + * may contain arbitrary data as negotiated between the app and the + * carrier. + * @return One of {@link MbmsException#SUCCESS}, + * {@link MbmsException#ERROR_MIDDLEWARE_NOT_BOUND}, + * {@link MbmsException#ERROR_CONCURRENT_SERVICE_LIMIT_REACHED} + */ @Override - public int getStreamingServices(String appName, int subId, List<String> serviceClasses) - throws RemoteException { + public int getStreamingServices(String appName, int subscriptionId, + List<String> serviceClasses) throws RemoteException { return 0; } + /** + * Starts streaming on a particular service. This method may perform asynchronous work. When + * the middleware is ready to send bits to the frontend, it should inform the app via + * {@link IStreamingServiceCallback#streamStateChanged(int)}. + * + * May throw an {@link IllegalArgumentException} or an {@link IllegalStateException} + * + * @param appName The app name as negotiated with the wireless carrier. + * @param subscriptionId The subscription id to use. + * @param serviceId The ID of the streaming service that the app has requested. + * @param listener The listener object on which the app wishes to receive updates. + * @return TODO: document possible errors + */ @Override - public int startStreaming(String appName, int subId, + public int startStreaming(String appName, int subscriptionId, String serviceId, IStreamingServiceCallback listener) throws RemoteException { return 0; } + /** + * Retrieves the streaming URI for a particular service. If the middleware is not yet ready to + * stream the service, this method may return null. + * + * May throw an {@link IllegalArgumentException} or an {@link IllegalStateException} + * + * @param appName The app name as negotiated with the wireless carrier. + * @param subscriptionId The subscription id to use. + * @param serviceId The ID of the streaming service that the app has requested. + * @return An opaque {@link Uri} to be passed to a video player that understands the format. + */ @Override - public int getActiveStreamingServices(String appName, int subId) throws RemoteException { - return 0; - } - - @Override - public Uri getPlaybackUri(String appName, int subId, String serviceId) throws RemoteException { - return null; - } - - @Override - public void switchStreams(String appName, int subId, String oldServiceId, String newServiceId) + public @Nullable Uri getPlaybackUri(String appName, int subscriptionId, String serviceId) throws RemoteException { - } - - @Override - public int getState(String appName, int subId, String serviceId) throws RemoteException { - return 0; + return null; } @Override diff --git a/telephony/java/com/android/ims/internal/IImsServiceController.aidl b/telephony/java/com/android/ims/internal/IImsServiceController.aidl index 712816f9d20c..bb06d7e085a7 100644 --- a/telephony/java/com/android/ims/internal/IImsServiceController.aidl +++ b/telephony/java/com/android/ims/internal/IImsServiceController.aidl @@ -37,7 +37,7 @@ import android.os.Message; interface IImsServiceController { // ImsService Control void createImsFeature(int slotId, int feature, IImsFeatureStatusCallback c); - void removeImsFeature(int slotId, int feature); + void removeImsFeature(int slotId, int feature, IImsFeatureStatusCallback c); // MMTel Feature int startSession(int slotId, int featureType, in PendingIntent incomingCallIntent, in IImsRegistrationListener listener); diff --git a/telephony/java/com/android/internal/telephony/ITelephony.aidl b/telephony/java/com/android/internal/telephony/ITelephony.aidl index f2e1e2691c8f..c5428791de6f 100644 --- a/telephony/java/com/android/internal/telephony/ITelephony.aidl +++ b/telephony/java/com/android/internal/telephony/ITelephony.aidl @@ -19,6 +19,8 @@ package com.android.internal.telephony; import android.app.PendingIntent; import android.content.Intent; import android.os.Bundle; +import android.os.IBinder; +import android.os.Messenger; import android.os.ResultReceiver; import android.net.Uri; import android.service.carrier.CarrierIdentifier; @@ -29,8 +31,10 @@ import android.telephony.ClientRequestStats; import android.telephony.IccOpenLogicalChannelResponse; import android.telephony.ModemActivityInfo; import android.telephony.NeighboringCellInfo; +import android.telephony.NetworkScanRequest; import android.telephony.RadioAccessFamily; import android.telephony.ServiceState; +import android.telephony.SignalStrength; import android.telephony.TelephonyHistogram; import android.telephony.VisualVoicemailSmsFilterSettings; import com.android.ims.internal.IImsServiceController; @@ -794,6 +798,26 @@ interface ITelephony { CellNetworkScanResult getCellNetworkScanResults(int subId); /** + * Perform a radio network scan and return the id of this scan. + * + * @param subId the id of the subscription. + * @param request Defines all the configs for network scan. + * @param messenger Callback messages will be sent using this messenger. + * @param binder the binder object instantiated in TelephonyManager. + * @return An id for this scan. + */ + int requestNetworkScan(int subId, in NetworkScanRequest request, in Messenger messenger, + in IBinder binder); + + /** + * Stop an existing radio network scan. + * + * @param subId the id of the subscription. + * @param scanId The id of the scan that is going to be stopped. + */ + void stopNetworkScan(int subId, int scanId); + + /** * Ask the radio to connect to the input network and change selection mode to manual. * * @param subId the id of the subscription. @@ -1267,12 +1291,12 @@ interface ITelephony { List<ClientRequestStats> getClientRequestStats(String callingPackage, int subid); /** - * Set SIM card power state. Request is equivalent to inserting or removing the card. + * Set SIM card power state. * @param slotIndex SIM slot id - * @param powerUp True if powering up the SIM, otherwise powering down + * @param state State of SIM (power down, power up, pass through) * @hide * */ - void setSimPowerStateForSlot(int slotIndex, boolean powerUp); + void setSimPowerStateForSlot(int slotIndex, int state); /** * Returns a list of Forbidden PLMNs from the specified SIM App @@ -1293,4 +1317,15 @@ interface ITelephony { * @hide */ boolean getEmergencyCallbackMode(int subId); + + /** + * Get the most recently available signal strength information. + * + * Get the most recent SignalStrength information reported by the modem. Due + * to power saving this information may not always be current. + * @param subId Subscription index + * @return the most recent cached signal strength info from the modem + * @hide + */ + SignalStrength getSignalStrength(int subId); } diff --git a/telephony/java/com/android/internal/telephony/NetworkScanResult.java b/telephony/java/com/android/internal/telephony/NetworkScanResult.java new file mode 100644 index 000000000000..0099961190e1 --- /dev/null +++ b/telephony/java/com/android/internal/telephony/NetworkScanResult.java @@ -0,0 +1,129 @@ +/* + * 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 com.android.internal.telephony; + +import android.os.Parcel; +import android.os.Parcelable; +import android.telephony.CellInfo; +import java.util.Arrays; +import java.util.ArrayList; +import java.util.List; + +/** + * Defines the incremental network scan result. + * + * This class contains the network scan results. When the user starts a new scan, multiple + * NetworkScanResult may be returned, containing either the scan result or error. When the user + * stops an ongoing scan, only one NetworkScanResult will be returned to indicate either the scan + * is now complete or there is some error stopping it. + * @hide + */ +public final class NetworkScanResult implements Parcelable { + + // Contains only part of the scan result and more are coming. + public static final int SCAN_STATUS_PARTIAL = 0; + + // Contains the last part of the scan result and the scan is now complete. + public static final int SCAN_STATUS_COMPLETE = 1; + + // The status of the scan, only valid when scanError = SUCCESS. + public int scanStatus; + + /** + * The error code of the scan + * + * This is the error code returned from the RIL, see {@link RILConstants} for more details + */ + public int scanError; + + // The scan results, only valid when scanError = SUCCESS. + public List<CellInfo> networkInfos; + + /** + * Creates a new NetworkScanResult with scanStatus, scanError and networkInfos + * + * @param scanStatus The status of the scan. + * @param scanError The error code of the scan. + * @param networkInfos List of the CellInfo. + */ + public NetworkScanResult(int scanStatus, int scanError, List<CellInfo> networkInfos) { + this.scanStatus = scanStatus; + this.scanError = scanError; + this.networkInfos = networkInfos; + } + + @Override + public int describeContents() { + return 0; + } + + @Override + public void writeToParcel(Parcel dest, int flags) { + dest.writeInt(scanStatus); + dest.writeInt(scanError); + CellInfo[] ci = networkInfos.toArray(new CellInfo[networkInfos.size()]); + dest.writeParcelableArray(ci, flags); + } + + private NetworkScanResult(Parcel in) { + scanStatus = in.readInt(); + scanError = in.readInt(); + CellInfo[] ci = (CellInfo[]) in.readParcelableArray( + Object.class.getClassLoader(), + CellInfo.class); + networkInfos = Arrays.asList(ci); + } + + @Override + public boolean equals (Object o) { + NetworkScanResult nsr; + + try { + nsr = (NetworkScanResult) o; + } catch (ClassCastException ex) { + return false; + } + + if (o == null) { + return false; + } + + return (scanStatus == nsr.scanStatus + && scanError == nsr.scanError + && networkInfos.equals(nsr.networkInfos)); + } + + @Override + public int hashCode () { + return ((scanStatus * 31) + + (scanError * 23) + + (networkInfos.hashCode() * 37)); + } + + public static final Creator<NetworkScanResult> CREATOR = + new Creator<NetworkScanResult>() { + @Override + public NetworkScanResult createFromParcel(Parcel in) { + return new NetworkScanResult(in); + } + + @Override + public NetworkScanResult[] newArray(int size) { + return new NetworkScanResult[size]; + } + }; +} diff --git a/telephony/java/com/android/internal/telephony/RILConstants.java b/telephony/java/com/android/internal/telephony/RILConstants.java index 954b17f744f2..e2d25b8e352c 100644 --- a/telephony/java/com/android/internal/telephony/RILConstants.java +++ b/telephony/java/com/android/internal/telephony/RILConstants.java @@ -415,6 +415,8 @@ cat include/telephony/ril.h | \ int RIL_REQUEST_SET_UNSOLICITED_RESPONSE_FILTER = 139; int RIL_REQUEST_SET_SIM_CARD_POWER = 140; int RIL_REQUEST_SET_CARRIER_INFO_IMSI_ENCRYPTION = 141; + int RIL_REQUEST_START_NETWORK_SCAN = 142; + int RIL_REQUEST_STOP_NETWORK_SCAN = 143; int RIL_RESPONSE_ACKNOWLEDGEMENT = 800; @@ -466,5 +468,7 @@ cat include/telephony/ril.h | \ int RIL_UNSOL_STK_CC_ALPHA_NOTIFY = 1044; int RIL_UNSOL_LCEDATA_RECV = 1045; int RIL_UNSOL_PCO_DATA = 1046; - int RIL_UNSOL_CARRIER_INFO_IMSI_ENCRYPTION = 1047; + int RIL_UNSOL_MODEM_RESTART = 1047; + int RIL_UNSOL_CARRIER_INFO_IMSI_ENCRYPTION = 1048; + int RIL_UNSOL_NETWORK_SCAN_RESULT = 1049; } diff --git a/test-runner/src/android/test/AndroidTestRunner.java b/test-runner/src/android/test/AndroidTestRunner.java index 50eaafbae39d..7313a2880ea2 100644 --- a/test-runner/src/android/test/AndroidTestRunner.java +++ b/test-runner/src/android/test/AndroidTestRunner.java @@ -20,8 +20,7 @@ import android.app.Instrumentation; import android.content.Context; import android.os.PerformanceCollector.PerformanceResultsWriter; -import com.google.android.collect.Lists; - +import java.util.ArrayList; import junit.framework.Test; import junit.framework.TestCase; import junit.framework.TestListener; @@ -48,7 +47,7 @@ public class AndroidTestRunner extends BaseTestRunner { private Context mContext; private boolean mSkipExecution = false; - private List<TestListener> mTestListeners = Lists.newArrayList(); + private List<TestListener> mTestListeners = new ArrayList<>(); private Instrumentation mInstrumentation; private PerformanceResultsWriter mPerfWriter; @@ -58,7 +57,8 @@ public class AndroidTestRunner extends BaseTestRunner { if (shouldRunSingleTestMethod(testMethodName, testClass)) { TestCase testCase = buildSingleTestMethod(testClass, testMethodName); - mTestCases = Lists.newArrayList(testCase); + mTestCases = new ArrayList<>(); + mTestCases.add(testCase); mTestClassName = testClass.getSimpleName(); } else { setTest(getTest(testClass), testClass); diff --git a/test-runner/src/android/test/ClassPathPackageInfo.java b/test-runner/src/android/test/ClassPathPackageInfo.java index 1ab7c7faeca4..2cf76afa1d94 100644 --- a/test-runner/src/android/test/ClassPathPackageInfo.java +++ b/test-runner/src/android/test/ClassPathPackageInfo.java @@ -16,9 +16,8 @@ package android.test; -import com.google.android.collect.Sets; - import java.util.Collections; +import java.util.HashSet; import java.util.Set; /** @@ -44,7 +43,7 @@ public class ClassPathPackageInfo { } public Set<ClassPathPackageInfo> getSubpackages() { - Set<ClassPathPackageInfo> info = Sets.newHashSet(); + Set<ClassPathPackageInfo> info = new HashSet<>(); for (String name : subpackageNames) { info.add(source.getPackageInfo(name)); } @@ -52,7 +51,7 @@ public class ClassPathPackageInfo { } public Set<Class<?>> getTopLevelClassesRecursive() { - Set<Class<?>> set = Sets.newHashSet(); + Set<Class<?>> set = new HashSet<>(); addTopLevelClassesTo(set); return set; } diff --git a/test-runner/src/android/test/ClassPathPackageInfoSource.java b/test-runner/src/android/test/ClassPathPackageInfoSource.java index 89bb494e02dd..9bcc25adf8d3 100644 --- a/test-runner/src/android/test/ClassPathPackageInfoSource.java +++ b/test-runner/src/android/test/ClassPathPackageInfoSource.java @@ -17,13 +17,13 @@ package android.test; import android.util.Log; -import com.google.android.collect.Maps; -import com.google.android.collect.Sets; import dalvik.system.DexFile; import java.io.File; import java.io.IOException; import java.util.Enumeration; +import java.util.HashMap; +import java.util.HashSet; import java.util.Map; import java.util.Set; import java.util.TreeSet; @@ -57,7 +57,7 @@ public class ClassPathPackageInfoSource { private static String[] apkPaths; // A cache of jar file contents - private final Map<File, Set<String>> jarFiles = Maps.newHashMap(); + private final Map<File, Set<String>> jarFiles = new HashMap<>(); private ClassLoader classLoader; ClassPathPackageInfoSource() { @@ -76,7 +76,7 @@ public class ClassPathPackageInfoSource { private ClassPathPackageInfo createPackageInfo(String packageName) { Set<String> subpackageNames = new TreeSet<String>(); Set<String> classNames = new TreeSet<String>(); - Set<Class<?>> topLevelClasses = Sets.newHashSet(); + Set<Class<?>> topLevelClasses = new HashSet<>(); findClasses(packageName, classNames, subpackageNames); for (String className : classNames) { if (className.endsWith(".R") || className.endsWith(".Manifest")) { @@ -248,7 +248,7 @@ public class ClassPathPackageInfoSource { throws IOException { Set<String> entryNames = jarFiles.get(jarFile); if (entryNames == null) { - entryNames = Sets.newHashSet(); + entryNames = new HashSet<>(); ZipFile zipFile = new ZipFile(jarFile); Enumeration<? extends ZipEntry> entries = zipFile.entries(); while (entries.hasMoreElements()) { diff --git a/test-runner/src/android/test/DatabaseTestUtils.java b/test-runner/src/android/test/DatabaseTestUtils.java index 42ef48b38a24..1980d921664d 100644 --- a/test-runner/src/android/test/DatabaseTestUtils.java +++ b/test-runner/src/android/test/DatabaseTestUtils.java @@ -16,11 +16,10 @@ package android.test; -import com.google.android.collect.Sets; - import android.database.sqlite.SQLiteDatabase; import android.database.Cursor; +import java.util.HashSet; import java.util.Set; /** @@ -42,7 +41,7 @@ public class DatabaseTestUtils { } private static Set<String> getSchemaSet(SQLiteDatabase db) { - Set<String> schemaSet = Sets.newHashSet(); + Set<String> schemaSet = new HashSet<>(); Cursor entityCursor = db.rawQuery("SELECT sql FROM sqlite_master", null); try { diff --git a/test-runner/src/android/test/IsolatedContext.java b/test-runner/src/android/test/IsolatedContext.java index 3abf38f3b224..0b77c0062dfb 100644 --- a/test-runner/src/android/test/IsolatedContext.java +++ b/test-runner/src/android/test/IsolatedContext.java @@ -16,8 +16,6 @@ package android.test; -import com.google.android.collect.Lists; - import android.accounts.AccountManager; import android.accounts.AccountManagerCallback; import android.accounts.AccountManagerFuture; @@ -38,6 +36,7 @@ import android.os.Handler; import java.io.File; import java.io.IOException; +import java.util.ArrayList; import java.util.concurrent.TimeUnit; import java.util.List; @@ -55,7 +54,7 @@ public class IsolatedContext extends ContextWrapper { private ContentResolver mResolver; private final MockAccountManager mMockAccountManager; - private List<Intent> mBroadcastIntents = Lists.newArrayList(); + private List<Intent> mBroadcastIntents = new ArrayList<>(); public IsolatedContext( ContentResolver resolver, Context targetContext) { @@ -67,7 +66,7 @@ public class IsolatedContext extends ContextWrapper { /** Returns the list of intents that were broadcast since the last call to this method. */ public List<Intent> getAndClearBroadcastIntents() { List<Intent> intents = mBroadcastIntents; - mBroadcastIntents = Lists.newArrayList(); + mBroadcastIntents = new ArrayList<>(); return intents; } diff --git a/test-runner/src/android/test/RenamingDelegatingContext.java b/test-runner/src/android/test/RenamingDelegatingContext.java index 36786b09df26..fd3332154611 100644 --- a/test-runner/src/android/test/RenamingDelegatingContext.java +++ b/test-runner/src/android/test/RenamingDelegatingContext.java @@ -16,20 +16,24 @@ package android.test; -import com.google.android.collect.Sets; - import android.content.Context; import android.content.ContextWrapper; import android.content.ContentProvider; import android.database.DatabaseErrorHandler; import android.database.sqlite.SQLiteDatabase; -import android.os.FileUtils; import android.util.Log; import java.io.File; import java.io.FileInputStream; import java.io.FileNotFoundException; import java.io.FileOutputStream; +import java.io.IOException; +import java.nio.file.Files; +import java.nio.file.Paths; +import java.nio.file.attribute.PosixFilePermission; +import java.nio.file.attribute.PosixFilePermissions; +import java.util.EnumSet; +import java.util.HashSet; import java.util.Set; /** @@ -48,8 +52,8 @@ public class RenamingDelegatingContext extends ContextWrapper { private File mCacheDir; private final Object mSync = new Object(); - private Set<String> mDatabaseNames = Sets.newHashSet(); - private Set<String> mFileNames = Sets.newHashSet(); + private Set<String> mDatabaseNames = new HashSet<>(); + private Set<String> mFileNames = new HashSet<>(); public static <T extends ContentProvider> T providerWithRenamedContext( Class<T> contentProvider, Context c, String filePrefix) @@ -237,10 +241,14 @@ public class RenamingDelegatingContext extends ContextWrapper { Log.w("RenamingDelegatingContext", "Unable to create cache directory"); return null; } - FileUtils.setPermissions( - mCacheDir.getPath(), - FileUtils.S_IRWXU|FileUtils.S_IRWXG|FileUtils.S_IXOTH, - -1, -1); + try { + // Give the directory all possible permissions. + Files.setPosixFilePermissions(mCacheDir.toPath(), + EnumSet.allOf(PosixFilePermission.class)); + } catch (IOException e) { + Log.e("RenamingDelegatingContext", + "Could not set permissions of test cacheDir", e); + } } } return mCacheDir; diff --git a/test-runner/src/android/test/TestCaseUtil.java b/test-runner/src/android/test/TestCaseUtil.java index c46d403f1350..dc053a2359a0 100644 --- a/test-runner/src/android/test/TestCaseUtil.java +++ b/test-runner/src/android/test/TestCaseUtil.java @@ -16,8 +16,7 @@ package android.test; -import com.google.android.collect.Lists; - +import java.util.ArrayList; import junit.framework.Test; import junit.framework.TestCase; import junit.framework.TestSuite; @@ -44,7 +43,7 @@ public class TestCaseUtil { @SuppressWarnings("unchecked") public static List<String> getTestCaseNames(Test test, boolean flatten) { List<Test> tests = (List<Test>) getTests(test, flatten); - List<String> testCaseNames = Lists.newArrayList(); + List<String> testCaseNames = new ArrayList<>(); for (Test aTest : tests) { testCaseNames.add(getTestName(aTest)); } @@ -57,7 +56,7 @@ public class TestCaseUtil { private static List<? extends Test> getTests(Test test, boolean flatten, Set<Class<?>> seen) { - List<Test> testCases = Lists.newArrayList(); + List<Test> testCases = new ArrayList<>(); if (test != null) { Test workingTest = null; diff --git a/test-runner/src/android/test/TestRunner.java b/test-runner/src/android/test/TestRunner.java index beecc6fdd9de..ff045c3b4072 100644 --- a/test-runner/src/android/test/TestRunner.java +++ b/test-runner/src/android/test/TestRunner.java @@ -32,7 +32,6 @@ import junit.framework.TestSuite; import junit.framework.TestListener; import junit.framework.Test; import junit.framework.TestResult; -import com.google.android.collect.Lists; /** * Support class that actually runs a test. Android uses this class, @@ -54,7 +53,7 @@ public class TestRunner implements PerformanceTestCase.Intermediates { private int mMode = REGRESSION; - private List<Listener> mListeners = Lists.newArrayList(); + private List<Listener> mListeners = new ArrayList<>(); private int mPassed; private int mFailed; diff --git a/test-runner/src/android/test/mock/MockContentResolver.java b/test-runner/src/android/test/mock/MockContentResolver.java index d8e097756c66..a70152c8b732 100644 --- a/test-runner/src/android/test/mock/MockContentResolver.java +++ b/test-runner/src/android/test/mock/MockContentResolver.java @@ -23,8 +23,7 @@ import android.content.IContentProvider; import android.database.ContentObserver; import android.net.Uri; -import com.google.android.collect.Maps; - +import java.util.HashMap; import java.util.Map; /** @@ -67,7 +66,7 @@ public class MockContentResolver extends ContentResolver { */ public MockContentResolver(Context context) { super(context); - mProviders = Maps.newHashMap(); + mProviders = new HashMap<>(); } /** diff --git a/test-runner/src/android/test/suitebuilder/TestSuiteBuilder.java b/test-runner/src/android/test/suitebuilder/TestSuiteBuilder.java index 3b920cff30e0..cf6936bee643 100644 --- a/test-runner/src/android/test/suitebuilder/TestSuiteBuilder.java +++ b/test-runner/src/android/test/suitebuilder/TestSuiteBuilder.java @@ -21,7 +21,6 @@ import android.test.AndroidTestRunner; import android.test.TestCaseUtil; import android.util.Log; import com.android.internal.util.Predicate; -import com.google.android.collect.Lists; import static android.test.suitebuilder.TestGrouping.SORT_BY_FULLY_QUALIFIED_NAME; import static android.test.suitebuilder.TestPredicates.REJECT_SUPPRESSED; @@ -69,7 +68,7 @@ public class TestSuiteBuilder { public TestSuiteBuilder(String name, ClassLoader classLoader) { this.suiteName = name; this.testGrouping.setClassLoader(classLoader); - this.testCases = Lists.newArrayList(); + this.testCases = new ArrayList<>(); addRequirements(REJECT_SUPPRESSED); } diff --git a/test-runner/tests/src/android/test/AndroidTestRunnerTest.java b/test-runner/tests/src/android/test/AndroidTestRunnerTest.java index 05747049dd21..67235480fa6d 100644 --- a/test-runner/tests/src/android/test/AndroidTestRunnerTest.java +++ b/test-runner/tests/src/android/test/AndroidTestRunnerTest.java @@ -19,8 +19,7 @@ package android.test; import android.test.mock.MockContext; import android.test.suitebuilder.annotation.SmallTest; -import com.google.android.collect.Lists; - +import java.util.ArrayList; import junit.framework.TestCase; import junit.framework.AssertionFailedError; import junit.framework.Test; @@ -140,7 +139,7 @@ public class AndroidTestRunnerTest extends TestCase { public void testSetTestClassWithTestSuiteProvider() throws Exception { mAndroidTestRunner.setTestClassName(SampleTestSuiteProvider.class.getName(), null); List<TestCase> testCases = mAndroidTestRunner.getTestCases(); - List<String> testNames = Lists.newArrayList(); + List<String> testNames = new ArrayList<>(); for (TestCase testCase : testCases) { testNames.add(testCase.getName()); } @@ -152,7 +151,7 @@ public class AndroidTestRunnerTest extends TestCase { public void testSetTestClassWithTestSuite() throws Exception { mAndroidTestRunner.setTestClassName(SampleTestSuite.class.getName(), null); List<TestCase> testCases = mAndroidTestRunner.getTestCases(); - List<String> testNames = Lists.newArrayList(); + List<String> testNames = new ArrayList<>(); for (TestCase testCase : testCases) { testNames.add(testCase.getName()); } @@ -163,7 +162,7 @@ public class AndroidTestRunnerTest extends TestCase { String testMethodName = "testTwo"; mAndroidTestRunner.setTestClassName(TwoTestTestCase.class.getName(), testMethodName); List<TestCase> testCases = mAndroidTestRunner.getTestCases(); - List<String> testNames = Lists.newArrayList(); + List<String> testNames = new ArrayList<>(); for (TestCase testCase : testCases) { testNames.add(testCase.getName()); } @@ -255,7 +254,7 @@ public class AndroidTestRunnerTest extends TestCase { } private static class TestListenerStub implements TestListener { - List<String> testNames = Lists.newArrayList(); + List<String> testNames = new ArrayList<>(); public void addError(Test test, Throwable t) { } diff --git a/tests/net/java/android/net/ConnectivityManagerTest.java b/tests/net/java/android/net/ConnectivityManagerTest.java index ceb0135727de..cc792cc749d9 100644 --- a/tests/net/java/android/net/ConnectivityManagerTest.java +++ b/tests/net/java/android/net/ConnectivityManagerTest.java @@ -45,6 +45,7 @@ import static org.mockito.Mockito.times; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; +import android.app.PendingIntent; import android.net.ConnectivityManager; import android.net.NetworkCapabilities; import android.content.Context; @@ -66,8 +67,6 @@ import org.mockito.ArgumentCaptor; import org.mockito.Mock; import org.mockito.MockitoAnnotations; - - @RunWith(AndroidJUnit4.class) @SmallTest public class ConnectivityManagerTest { @@ -296,6 +295,43 @@ public class ConnectivityManagerTest { manager.requestNetwork(request, callback); } + @Test + public void testArgumentValidation() throws Exception { + ConnectivityManager manager = new ConnectivityManager(mCtx, mService); + + NetworkRequest request = mock(NetworkRequest.class); + NetworkCallback callback = mock(NetworkCallback.class); + Handler handler = mock(Handler.class); + NetworkCallback nullCallback = null; + PendingIntent nullIntent = null; + + mustFail(() -> { manager.requestNetwork(null, callback); }); + mustFail(() -> { manager.requestNetwork(request, nullCallback); }); + mustFail(() -> { manager.requestNetwork(request, callback, null); }); + mustFail(() -> { manager.requestNetwork(request, callback, -1); }); + mustFail(() -> { manager.requestNetwork(request, nullIntent); }); + + mustFail(() -> { manager.registerNetworkCallback(null, callback, handler); }); + mustFail(() -> { manager.registerNetworkCallback(request, null, handler); }); + mustFail(() -> { manager.registerNetworkCallback(request, callback, null); }); + mustFail(() -> { manager.registerNetworkCallback(request, nullIntent); }); + + mustFail(() -> { manager.registerDefaultNetworkCallback(null, handler); }); + mustFail(() -> { manager.registerDefaultNetworkCallback(callback, null); }); + + mustFail(() -> { manager.unregisterNetworkCallback(nullCallback); }); + mustFail(() -> { manager.unregisterNetworkCallback(nullIntent); }); + mustFail(() -> { manager.releaseNetworkRequest(nullIntent); }); + } + + static void mustFail(Runnable fn) { + try { + fn.run(); + fail(); + } catch (Exception expected) { + } + } + static Message makeMessage(NetworkRequest req, int messageType) { Bundle bundle = new Bundle(); bundle.putParcelable(NetworkRequest.class.getSimpleName(), req); diff --git a/tests/net/java/com/android/server/ConnectivityServiceTest.java b/tests/net/java/com/android/server/ConnectivityServiceTest.java index 517327882bfa..3c0b8aa7c59d 100644 --- a/tests/net/java/com/android/server/ConnectivityServiceTest.java +++ b/tests/net/java/com/android/server/ConnectivityServiceTest.java @@ -43,6 +43,7 @@ import android.net.ConnectivityManager; import android.net.ConnectivityManager.NetworkCallback; import android.net.ConnectivityManager.PacketKeepalive; import android.net.ConnectivityManager.PacketKeepaliveCallback; +import android.net.ConnectivityManager.TooManyRequestsException; import android.net.INetworkPolicyManager; import android.net.INetworkStatsService; import android.net.IpPrefix; @@ -2981,7 +2982,7 @@ public class ConnectivityServiceTest extends AndroidTestCase { networkCallbacks.add(networkCallback); } fail("Registering " + MAX_REQUESTS + " NetworkRequests did not throw exception"); - } catch (IllegalArgumentException expected) {} + } catch (TooManyRequestsException expected) {} for (NetworkCallback networkCallback : networkCallbacks) { mCm.unregisterNetworkCallback(networkCallback); } @@ -2994,7 +2995,7 @@ public class ConnectivityServiceTest extends AndroidTestCase { networkCallbacks.add(networkCallback); } fail("Registering " + MAX_REQUESTS + " NetworkCallbacks did not throw exception"); - } catch (IllegalArgumentException expected) {} + } catch (TooManyRequestsException expected) {} for (NetworkCallback networkCallback : networkCallbacks) { mCm.unregisterNetworkCallback(networkCallback); } @@ -3010,7 +3011,7 @@ public class ConnectivityServiceTest extends AndroidTestCase { } fail("Registering " + MAX_REQUESTS + " PendingIntent NetworkRequests did not throw exception"); - } catch (IllegalArgumentException expected) {} + } catch (TooManyRequestsException expected) {} for (PendingIntent pendingIntent : pendingIntents) { mCm.unregisterNetworkCallback(pendingIntent); } @@ -3025,7 +3026,7 @@ public class ConnectivityServiceTest extends AndroidTestCase { } fail("Registering " + MAX_REQUESTS + " PendingIntent NetworkCallbacks did not throw exception"); - } catch (IllegalArgumentException expected) {} + } catch (TooManyRequestsException expected) {} for (PendingIntent pendingIntent : pendingIntents) { mCm.unregisterNetworkCallback(pendingIntent); } diff --git a/tests/net/java/com/android/server/connectivity/TetheringTest.java b/tests/net/java/com/android/server/connectivity/TetheringTest.java index 3172c6ec856a..bc89c0f4f71f 100644 --- a/tests/net/java/com/android/server/connectivity/TetheringTest.java +++ b/tests/net/java/com/android/server/connectivity/TetheringTest.java @@ -56,6 +56,8 @@ import android.support.test.runner.AndroidJUnit4; import android.telephony.CarrierConfigManager; import com.android.internal.util.test.BroadcastInterceptingContext; +import com.android.server.connectivity.tethering.OffloadHardwareInterface; +import com.android.server.connectivity.tethering.TetheringDependencies; import org.junit.After; import org.junit.Before; @@ -78,7 +80,9 @@ public class TetheringTest { @Mock private INetworkStatsService mStatsService; @Mock private INetworkPolicyManager mPolicyManager; @Mock private MockableSystemProperties mSystemProperties; + @Mock private OffloadHardwareInterface mOffloadHardwareInterface; @Mock private Resources mResources; + @Mock private TetheringDependencies mTetheringDependencies; @Mock private UsbManager mUsbManager; @Mock private WifiManager mWifiManager; @Mock private CarrierConfigManager mCarrierConfigManager; @@ -138,8 +142,11 @@ public class TetheringTest { }; mServiceContext.registerReceiver(mBroadcastReceiver, new IntentFilter(ConnectivityManager.ACTION_TETHER_STATE_CHANGED)); + when(mTetheringDependencies.getOffloadHardwareInterface()) + .thenReturn(mOffloadHardwareInterface); mTethering = new Tethering(mServiceContext, mNMService, mStatsService, mPolicyManager, - mLooper.getLooper(), mSystemProperties); + mLooper.getLooper(), mSystemProperties, + mTetheringDependencies); } @After diff --git a/tests/net/java/com/android/server/connectivity/tethering/TetheringConfigurationTest.java b/tests/net/java/com/android/server/connectivity/tethering/TetheringConfigurationTest.java new file mode 100644 index 000000000000..9fcd1b52b8fe --- /dev/null +++ b/tests/net/java/com/android/server/connectivity/tethering/TetheringConfigurationTest.java @@ -0,0 +1,132 @@ +/* + * 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 com.android.server.connectivity.tethering; + +import static android.net.ConnectivityManager.TYPE_MOBILE; +import static android.net.ConnectivityManager.TYPE_MOBILE_DUN; +import static android.net.ConnectivityManager.TYPE_MOBILE_HIPRI; +import static android.net.ConnectivityManager.TYPE_WIFI; +import static com.android.server.connectivity.tethering.TetheringConfiguration.DUN_NOT_REQUIRED; +import static com.android.server.connectivity.tethering.TetheringConfiguration.DUN_REQUIRED; +import static com.android.server.connectivity.tethering.TetheringConfiguration.DUN_UNSPECIFIED; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertTrue; +import static org.mockito.Mockito.when; + +import android.content.Context; +import android.content.ContextWrapper; +import android.content.res.Resources; +import android.support.test.filters.SmallTest; +import android.support.test.runner.AndroidJUnit4; +import android.telephony.TelephonyManager; + +import com.android.internal.util.test.BroadcastInterceptingContext; + +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.Mock; +import org.mockito.MockitoAnnotations; + + +@RunWith(AndroidJUnit4.class) +@SmallTest +public class TetheringConfigurationTest { + @Mock private Context mContext; + @Mock private TelephonyManager mTelephonyManager; + @Mock private Resources mResources; + private Context mMockContext; + private boolean mHasTelephonyManager; + + private class MockContext extends BroadcastInterceptingContext { + MockContext(Context base) { + super(base); + } + + @Override + public Resources getResources() { return mResources; } + + @Override + public Object getSystemService(String name) { + if (Context.TELEPHONY_SERVICE.equals(name)) { + return mHasTelephonyManager ? mTelephonyManager : null; + } + return super.getSystemService(name); + } + } + + @Before + public void setUp() throws Exception { + MockitoAnnotations.initMocks(this); + when(mResources.getStringArray(com.android.internal.R.array.config_tether_dhcp_range)) + .thenReturn(new String[0]); + when(mResources.getStringArray(com.android.internal.R.array.config_tether_usb_regexs)) + .thenReturn(new String[0]); + when(mResources.getStringArray(com.android.internal.R.array.config_tether_wifi_regexs)) + .thenReturn(new String[]{ "test_wlan\\d" }); + when(mResources.getStringArray(com.android.internal.R.array.config_tether_bluetooth_regexs)) + .thenReturn(new String[0]); + mMockContext = new MockContext(mContext); + } + + @Test + public void testDunFromTelephonyManagerMeansDun() { + when(mResources.getIntArray(com.android.internal.R.array.config_tether_upstream_types)) + .thenReturn(new int[]{TYPE_MOBILE, TYPE_WIFI, TYPE_MOBILE_HIPRI}); + mHasTelephonyManager = true; + when(mTelephonyManager.getTetherApnRequired()).thenReturn(DUN_REQUIRED); + + final TetheringConfiguration cfg = new TetheringConfiguration(mMockContext); + assertTrue(cfg.isDunRequired); + assertTrue(cfg.preferredUpstreamIfaceTypes.contains(TYPE_MOBILE_DUN)); + assertFalse(cfg.preferredUpstreamIfaceTypes.contains(TYPE_MOBILE)); + assertFalse(cfg.preferredUpstreamIfaceTypes.contains(TYPE_MOBILE_HIPRI)); + // Just to prove we haven't clobbered Wi-Fi: + assertTrue(cfg.preferredUpstreamIfaceTypes.contains(TYPE_WIFI)); + } + + @Test + public void testDunNotRequiredFromTelephonyManagerMeansNoDun() { + when(mResources.getIntArray(com.android.internal.R.array.config_tether_upstream_types)) + .thenReturn(new int[]{TYPE_MOBILE_DUN, TYPE_WIFI}); + mHasTelephonyManager = true; + when(mTelephonyManager.getTetherApnRequired()).thenReturn(DUN_NOT_REQUIRED); + + final TetheringConfiguration cfg = new TetheringConfiguration(mMockContext); + assertFalse(cfg.isDunRequired); + assertFalse(cfg.preferredUpstreamIfaceTypes.contains(TYPE_MOBILE_DUN)); + assertTrue(cfg.preferredUpstreamIfaceTypes.contains(TYPE_MOBILE)); + assertTrue(cfg.preferredUpstreamIfaceTypes.contains(TYPE_MOBILE_HIPRI)); + // Just to prove we haven't clobbered Wi-Fi: + assertTrue(cfg.preferredUpstreamIfaceTypes.contains(TYPE_WIFI)); + } + + @Test + public void testDunFromUpstreamConfigMeansDun() { + when(mResources.getIntArray(com.android.internal.R.array.config_tether_upstream_types)) + .thenReturn(new int[]{TYPE_MOBILE_DUN, TYPE_WIFI}); + mHasTelephonyManager = false; + when(mTelephonyManager.getTetherApnRequired()).thenReturn(DUN_UNSPECIFIED); + + final TetheringConfiguration cfg = new TetheringConfiguration(mMockContext); + assertTrue(cfg.isDunRequired); + assertTrue(cfg.preferredUpstreamIfaceTypes.contains(TYPE_MOBILE_DUN)); + // Just to prove we haven't clobbered Wi-Fi: + assertTrue(cfg.preferredUpstreamIfaceTypes.contains(TYPE_WIFI)); + } +} |