diff options
41 files changed, 553 insertions, 218 deletions
diff --git a/api/current.txt b/api/current.txt index 8216304..578f808 100644 --- a/api/current.txt +++ b/api/current.txt @@ -18299,17 +18299,18 @@ package android.net { method public boolean bindProcessToNetwork(android.net.Network); method public android.net.Network getActiveNetwork(); method public android.net.NetworkInfo getActiveNetworkInfo(); - method public android.net.NetworkInfo[] getAllNetworkInfo(); + method public deprecated android.net.NetworkInfo[] getAllNetworkInfo(); method public android.net.Network[] getAllNetworks(); method public deprecated boolean getBackgroundDataSetting(); method public android.net.Network getBoundNetworkForProcess(); method public android.net.ProxyInfo getDefaultProxy(); method public android.net.LinkProperties getLinkProperties(android.net.Network); method public android.net.NetworkCapabilities getNetworkCapabilities(android.net.Network); - method public android.net.NetworkInfo getNetworkInfo(int); + method public deprecated android.net.NetworkInfo getNetworkInfo(int); method public android.net.NetworkInfo getNetworkInfo(android.net.Network); method public deprecated int getNetworkPreference(); method public static deprecated android.net.Network getProcessDefaultNetwork(); + method public void ignoreNetworkWithCaptivePortal(android.net.Network, java.lang.String); method public boolean isActiveNetworkMetered(); method public boolean isDefaultNetworkActive(); method public static boolean isNetworkTypeValid(int); @@ -18317,6 +18318,7 @@ package android.net { method public void releaseNetworkRequest(android.app.PendingIntent); method public void removeDefaultNetworkActiveListener(android.net.ConnectivityManager.OnNetworkActiveListener); method public deprecated void reportBadNetwork(android.net.Network); + method public void reportCaptivePortalDismissed(android.net.Network, java.lang.String); method public void reportNetworkConnectivity(android.net.Network, boolean); method public void requestNetwork(android.net.NetworkRequest, android.net.ConnectivityManager.NetworkCallback); method public void requestNetwork(android.net.NetworkRequest, android.app.PendingIntent); @@ -18324,8 +18326,10 @@ package android.net { method public static deprecated boolean setProcessDefaultNetwork(android.net.Network); method public void unregisterNetworkCallback(android.net.ConnectivityManager.NetworkCallback); field public static final deprecated java.lang.String ACTION_BACKGROUND_DATA_SETTING_CHANGED = "android.net.conn.BACKGROUND_DATA_SETTING_CHANGED"; + field public static final java.lang.String ACTION_CAPTIVE_PORTAL_SIGN_IN = "android.net.conn.CAPTIVE_PORTAL"; field public static final java.lang.String CONNECTIVITY_ACTION = "android.net.conn.CONNECTIVITY_CHANGE"; field public static final deprecated int DEFAULT_NETWORK_PREFERENCE = 1; // 0x1 + field public static final java.lang.String EXTRA_CAPTIVE_PORTAL_TOKEN = "captivePortalToken"; field public static final java.lang.String EXTRA_EXTRA_INFO = "extraInfo"; field public static final java.lang.String EXTRA_IS_FAILOVER = "isFailover"; field public static final java.lang.String EXTRA_NETWORK = "android.net.extra.NETWORK"; @@ -19286,8 +19290,6 @@ package android.net.wifi { field public java.util.BitSet allowedKeyManagement; field public java.util.BitSet allowedPairwiseCiphers; field public java.util.BitSet allowedProtocols; - field public int apBand; - field public int apChannel; field public android.net.wifi.WifiEnterpriseConfig enterpriseConfig; field public boolean hiddenSSID; field public int networkId; @@ -19356,6 +19358,7 @@ package android.net.wifi { method public java.lang.String getAnonymousIdentity(); method public java.security.cert.X509Certificate getCaCertificate(); method public java.security.cert.X509Certificate getClientCertificate(); + method public java.lang.String getDomainSubjectMatch(); method public int getEapMethod(); method public java.lang.String getIdentity(); method public java.lang.String getPassword(); @@ -19367,6 +19370,7 @@ package android.net.wifi { method public void setAnonymousIdentity(java.lang.String); method public void setCaCertificate(java.security.cert.X509Certificate); method public void setClientKeyEntry(java.security.PrivateKey, java.security.cert.X509Certificate); + method public void setDomainSuffixMatch(java.lang.String); method public void setEapMethod(int); method public void setIdentity(java.lang.String); method public void setPassword(java.lang.String); @@ -30218,6 +30222,7 @@ package android.telecom { method public final android.telecom.PhoneAccountHandle getPhoneAccountHandle(); method public android.telecom.Connection getPrimaryConnection(); method public final int getState(); + method public final android.telecom.StatusHints getStatusHints(); method public void onAudioStateChanged(android.telecom.AudioState); method public void onConnectionAdded(android.telecom.Connection); method public void onDisconnect(); @@ -30236,6 +30241,7 @@ package android.telecom { method public final void setConnectionCapabilities(int); method public final void setDisconnected(android.telecom.DisconnectCause); method public final void setOnHold(); + method public final void setStatusHints(android.telecom.StatusHints); field public static final long CONNECT_TIME_NOT_SPECIFIED = 0L; // 0x0L } @@ -30426,6 +30432,7 @@ package android.telecom { public static abstract class InCallService.VideoCall { ctor public InCallService.VideoCall(); method public abstract void registerCallback(android.telecom.InCallService.VideoCall.Callback); + method public abstract void unregisterCallback(); method public abstract void requestCallDataUsage(); method public abstract void requestCameraCapabilities(); method public abstract void sendSessionModifyRequest(android.telecom.VideoProfile); diff --git a/api/system-current.txt b/api/system-current.txt index 09d32da..2ea68c6 100644 --- a/api/system-current.txt +++ b/api/system-current.txt @@ -19758,17 +19758,18 @@ package android.net { method public boolean bindProcessToNetwork(android.net.Network); method public android.net.Network getActiveNetwork(); method public android.net.NetworkInfo getActiveNetworkInfo(); - method public android.net.NetworkInfo[] getAllNetworkInfo(); + method public deprecated android.net.NetworkInfo[] getAllNetworkInfo(); method public android.net.Network[] getAllNetworks(); method public deprecated boolean getBackgroundDataSetting(); method public android.net.Network getBoundNetworkForProcess(); method public android.net.ProxyInfo getDefaultProxy(); method public android.net.LinkProperties getLinkProperties(android.net.Network); method public android.net.NetworkCapabilities getNetworkCapabilities(android.net.Network); - method public android.net.NetworkInfo getNetworkInfo(int); + method public deprecated android.net.NetworkInfo getNetworkInfo(int); method public android.net.NetworkInfo getNetworkInfo(android.net.Network); method public deprecated int getNetworkPreference(); method public static deprecated android.net.Network getProcessDefaultNetwork(); + method public void ignoreNetworkWithCaptivePortal(android.net.Network, java.lang.String); method public boolean isActiveNetworkMetered(); method public boolean isDefaultNetworkActive(); method public static boolean isNetworkTypeValid(int); @@ -19776,6 +19777,7 @@ package android.net { method public void releaseNetworkRequest(android.app.PendingIntent); method public void removeDefaultNetworkActiveListener(android.net.ConnectivityManager.OnNetworkActiveListener); method public deprecated void reportBadNetwork(android.net.Network); + method public void reportCaptivePortalDismissed(android.net.Network, java.lang.String); method public void reportNetworkConnectivity(android.net.Network, boolean); method public void requestNetwork(android.net.NetworkRequest, android.net.ConnectivityManager.NetworkCallback); method public void requestNetwork(android.net.NetworkRequest, android.app.PendingIntent); @@ -19783,8 +19785,10 @@ package android.net { method public static deprecated boolean setProcessDefaultNetwork(android.net.Network); method public void unregisterNetworkCallback(android.net.ConnectivityManager.NetworkCallback); field public static final deprecated java.lang.String ACTION_BACKGROUND_DATA_SETTING_CHANGED = "android.net.conn.BACKGROUND_DATA_SETTING_CHANGED"; + field public static final java.lang.String ACTION_CAPTIVE_PORTAL_SIGN_IN = "android.net.conn.CAPTIVE_PORTAL"; field public static final java.lang.String CONNECTIVITY_ACTION = "android.net.conn.CONNECTIVITY_CHANGE"; field public static final deprecated int DEFAULT_NETWORK_PREFERENCE = 1; // 0x1 + field public static final java.lang.String EXTRA_CAPTIVE_PORTAL_TOKEN = "captivePortalToken"; field public static final java.lang.String EXTRA_EXTRA_INFO = "extraInfo"; field public static final java.lang.String EXTRA_IS_FAILOVER = "isFailover"; field public static final java.lang.String EXTRA_NETWORK = "android.net.extra.NETWORK"; @@ -20985,8 +20989,6 @@ package android.net.wifi { field public java.util.BitSet allowedKeyManagement; field public java.util.BitSet allowedPairwiseCiphers; field public java.util.BitSet allowedProtocols; - field public int apBand; - field public int apChannel; field public java.lang.String creatorName; field public int creatorUid; field public android.net.wifi.WifiEnterpriseConfig enterpriseConfig; @@ -21077,6 +21079,7 @@ package android.net.wifi { method public java.lang.String getAnonymousIdentity(); method public java.security.cert.X509Certificate getCaCertificate(); method public java.security.cert.X509Certificate getClientCertificate(); + method public java.lang.String getDomainSubjectMatch(); method public int getEapMethod(); method public java.lang.String getIdentity(); method public java.lang.String getPassword(); @@ -21088,6 +21091,7 @@ package android.net.wifi { method public void setAnonymousIdentity(java.lang.String); method public void setCaCertificate(java.security.cert.X509Certificate); method public void setClientKeyEntry(java.security.PrivateKey, java.security.cert.X509Certificate); + method public void setDomainSuffixMatch(java.lang.String); method public void setEapMethod(int); method public void setIdentity(java.lang.String); method public void setPassword(java.lang.String); @@ -32329,6 +32333,7 @@ package android.telecom { method public final android.telecom.PhoneAccountHandle getPhoneAccountHandle(); method public android.telecom.Connection getPrimaryConnection(); method public final int getState(); + method public final android.telecom.StatusHints getStatusHints(); method public void onAudioStateChanged(android.telecom.AudioState); method public void onConnectionAdded(android.telecom.Connection); method public void onDisconnect(); @@ -32347,6 +32352,7 @@ package android.telecom { method public final void setConnectionCapabilities(int); method public final void setDisconnected(android.telecom.DisconnectCause); method public final void setOnHold(); + method public final void setStatusHints(android.telecom.StatusHints); field public static final long CONNECT_TIME_NOT_SPECIFIED = 0L; // 0x0L } @@ -32540,6 +32546,7 @@ package android.telecom { public static abstract class InCallService.VideoCall { ctor public InCallService.VideoCall(); method public abstract void registerCallback(android.telecom.InCallService.VideoCall.Callback); + method public abstract void unregisterCallback(); method public abstract void requestCallDataUsage(); method public abstract void requestCameraCapabilities(); method public abstract void sendSessionModifyRequest(android.telecom.VideoProfile); diff --git a/core/java/android/bluetooth/BluetoothAdapter.java b/core/java/android/bluetooth/BluetoothAdapter.java index 79e560f..d4e79be 100644 --- a/core/java/android/bluetooth/BluetoothAdapter.java +++ b/core/java/android/bluetooth/BluetoothAdapter.java @@ -121,6 +121,9 @@ public final class BluetoothAdapter { * {@link #STATE_TURNING_ON}, * {@link #STATE_ON}, * {@link #STATE_TURNING_OFF}, + * {@link #STATE_BLE_TURNING_ON}, + * {@link #STATE_BLE_ON}, + * {@link #STATE_BLE_TURNING_OFF}, */ public static final String EXTRA_STATE = "android.bluetooth.adapter.extra.STATE"; @@ -130,7 +133,7 @@ public final class BluetoothAdapter { * {@link #STATE_OFF}, * {@link #STATE_TURNING_ON}, * {@link #STATE_ON}, - * {@link #STATE_TURNING_OFF}, + * {@link #STATE_TURNING_OFF} */ public static final String EXTRA_PREVIOUS_STATE = "android.bluetooth.adapter.extra.PREVIOUS_STATE"; @@ -1301,9 +1304,12 @@ public final class BluetoothAdapter { public boolean isHardwareTrackingFiltersAvailable() { if (getState() != STATE_ON) return false; try { - synchronized(mManagerCallback) { - if(mService != null) return (mService.numOfHwTrackFiltersAvailable() != 0); + IBluetoothGatt iGatt = mManagerService.getBluetoothGatt(); + if (iGatt == null) { + // BLE is not supported + return false; } + return (iGatt.numHwTrackFiltersAvailable() != 0); } catch (RemoteException e) { Log.e(TAG, "", e); } diff --git a/core/java/android/bluetooth/BluetoothGattCallbackWrapper.java b/core/java/android/bluetooth/BluetoothGattCallbackWrapper.java index cdb24f4..01778b3 100644 --- a/core/java/android/bluetooth/BluetoothGattCallbackWrapper.java +++ b/core/java/android/bluetooth/BluetoothGattCallbackWrapper.java @@ -123,4 +123,7 @@ public class BluetoothGattCallbackWrapper extends IBluetoothGattCallback.Stub { public void onFoundOrLost(boolean onFound, ScanResult scanResult) throws RemoteException { } + @Override + public void onScanManagerErrorCallback(int errorCode) throws RemoteException { + } } diff --git a/core/java/android/bluetooth/IBluetooth.aidl b/core/java/android/bluetooth/IBluetooth.aidl index f6001bf..a3eceb5 100644 --- a/core/java/android/bluetooth/IBluetooth.aidl +++ b/core/java/android/bluetooth/IBluetooth.aidl @@ -100,7 +100,6 @@ interface IBluetooth boolean isActivityAndEnergyReportingSupported(); void getActivityEnergyInfoFromController(); BluetoothActivityEnergyInfo reportActivityInfo(); - int numOfHwTrackFiltersAvailable(); // for dumpsys support String dump(); diff --git a/core/java/android/bluetooth/IBluetoothGatt.aidl b/core/java/android/bluetooth/IBluetoothGatt.aidl index 4ca57f8..72abeaf 100644 --- a/core/java/android/bluetooth/IBluetoothGatt.aidl +++ b/core/java/android/bluetooth/IBluetoothGatt.aidl @@ -103,4 +103,5 @@ interface IBluetoothGatt { in boolean confirm, in byte[] value); void disconnectAll(); void unregAll(); + int numHwTrackFiltersAvailable(); } diff --git a/core/java/android/bluetooth/IBluetoothGattCallback.aidl b/core/java/android/bluetooth/IBluetoothGattCallback.aidl index 91e62ea..cbba9f0 100644 --- a/core/java/android/bluetooth/IBluetoothGattCallback.aidl +++ b/core/java/android/bluetooth/IBluetoothGattCallback.aidl @@ -67,6 +67,7 @@ oneway interface IBluetoothGattCallback { void onReadRemoteRssi(in String address, in int rssi, in int status); void onMultiAdvertiseCallback(in int status, boolean isStart, in AdvertiseSettings advertiseSettings); + void onScanManagerErrorCallback(in int errorCode); void onConfigureMTU(in String address, in int mtu, in int status); void onFoundOrLost(in boolean onFound, in ScanResult scanResult); } diff --git a/core/java/android/bluetooth/le/BluetoothLeScanner.java b/core/java/android/bluetooth/le/BluetoothLeScanner.java index 3078951..687bd5d 100644 --- a/core/java/android/bluetooth/le/BluetoothLeScanner.java +++ b/core/java/android/bluetooth/le/BluetoothLeScanner.java @@ -381,6 +381,18 @@ public final class BluetoothLeScanner { } }); } + + @Override + public void onScanManagerErrorCallback(final int errorCode) { + if (VDBG) { + Log.d(TAG, "onScanManagerErrorCallback() - errorCode = " + errorCode); + } + synchronized (this) { + if (mClientIf <= 0) + return; + } + postCallbackError(mScanCallback, errorCode); + } } private void postCallbackError(final ScanCallback callback, final int errorCode) { diff --git a/core/java/android/net/ConnectivityManager.java b/core/java/android/net/ConnectivityManager.java index 63f48cf..c531e7e 100644 --- a/core/java/android/net/ConnectivityManager.java +++ b/core/java/android/net/ConnectivityManager.java @@ -98,13 +98,41 @@ public class ConnectivityManager { public static final String CONNECTIVITY_ACTION = "android.net.conn.CONNECTIVITY_CHANGE"; /** + * The device has connected to a network that has presented a captive + * portal, which is blocking Internet connectivity. The user was presented + * with a notification that network sign in is required, + * and the user invoked the notification's action indicating they + * desire to sign in to the network. Apps handling this action should + * facilitate signing in to the network. This action includes a + * {@link Network} typed extra called {@link #EXTRA_NETWORK} that represents + * the network presenting the captive portal; all communication with the + * captive portal must be done using this {@code Network} object. + * <p/> + * When the app handling this action believes the user has signed in to + * the network and the captive portal has been dismissed, the app should call + * {@link #reportCaptivePortalDismissed} so the system can reevaluate the network. + * If reevaluation finds the network no longer subject to a captive portal, + * the network may become the default active data network. + * <p/> + * When the app handling this action believes the user explicitly wants + * to ignore the captive portal and the network, the app should call + * {@link #ignoreNetworkWithCaptivePortal}. + * <p/> + * Note that this action includes a {@code String} extra named + * {@link #EXTRA_CAPTIVE_PORTAL_TOKEN} that must + * be passed in to {@link #reportCaptivePortalDismissed} and + * {@link #ignoreNetworkWithCaptivePortal}. + */ + @SdkConstant(SdkConstantType.ACTIVITY_INTENT_ACTION) + public static final String ACTION_CAPTIVE_PORTAL_SIGN_IN = "android.net.conn.CAPTIVE_PORTAL"; + + /** * The lookup key for a {@link NetworkInfo} object. Retrieve with * {@link android.content.Intent#getParcelableExtra(String)}. * * @deprecated Since {@link NetworkInfo} can vary based on UID, applications * should always obtain network information through - * {@link #getActiveNetworkInfo()} or - * {@link #getAllNetworkInfo()}. + * {@link #getActiveNetworkInfo()}. * @see #EXTRA_NETWORK_TYPE */ @Deprecated @@ -112,8 +140,6 @@ public class ConnectivityManager { /** * Network type which triggered a {@link #CONNECTIVITY_ACTION} broadcast. - * Can be used with {@link #getNetworkInfo(int)} to get {@link NetworkInfo} - * state based on the calling application. * * @see android.content.Intent#getIntExtra(String, int) */ @@ -163,6 +189,15 @@ public class ConnectivityManager { public static final String EXTRA_INET_CONDITION = "inetCondition"; /** + * The lookup key for a string that is sent out with + * {@link #ACTION_CAPTIVE_PORTAL_SIGN_IN}. This string must be + * passed in to {@link #reportCaptivePortalDismissed} and + * {@link #ignoreNetworkWithCaptivePortal}. Retrieve it with + * {@link android.content.Intent#getStringExtra(String)}. + */ + public static final String EXTRA_CAPTIVE_PORTAL_TOKEN = "captivePortalToken"; + + /** * Broadcast action to indicate the change of data activity status * (idle or active) on a network in a recent period. * The network becomes active when data transmission is started, or @@ -660,6 +695,10 @@ public class ConnectivityManager { * * <p>This method requires the caller to hold the permission * {@link android.Manifest.permission#ACCESS_NETWORK_STATE}. + * + * @deprecated This method does not support multiple connected networks + * of the same type. Use {@link #getAllNetworks} and + * {@link #getNetworkInfo(android.net.Network)} instead. */ public NetworkInfo getNetworkInfo(int networkType) { try { @@ -699,6 +738,10 @@ public class ConnectivityManager { * * <p>This method requires the caller to hold the permission * {@link android.Manifest.permission#ACCESS_NETWORK_STATE}. + * + * @deprecated This method does not support multiple connected networks + * of the same type. Use {@link #getAllNetworks} and + * {@link #getNetworkInfo(android.net.Network)} instead. */ public NetworkInfo[] getAllNetworkInfo() { try { @@ -716,6 +759,9 @@ public class ConnectivityManager { * {@link android.Manifest.permission#ACCESS_NETWORK_STATE}. * * @hide + * @deprecated This method does not support multiple connected networks + * of the same type. Use {@link #getAllNetworks} and + * {@link #getNetworkInfo(android.net.Network)} instead. */ public Network getNetworkForType(int networkType) { try { @@ -808,6 +854,10 @@ public class ConnectivityManager { * <p>This method requires the caller to hold the permission * {@link android.Manifest.permission#ACCESS_NETWORK_STATE}. * {@hide} + * @deprecated This method does not support multiple connected networks + * of the same type. Use {@link #getAllNetworks}, + * {@link #getNetworkInfo(android.net.Network)}, and + * {@link #getLinkProperties(android.net.Network)} instead. */ public LinkProperties getLinkProperties(int networkType) { try { @@ -1748,6 +1798,82 @@ public class ConnectivityManager { } } + /** {@hide} */ + public static final int CAPTIVE_PORTAL_APP_RETURN_DISMISSED = 0; + /** {@hide} */ + public static final int CAPTIVE_PORTAL_APP_RETURN_UNWANTED = 1; + /** {@hide} */ + public static final int CAPTIVE_PORTAL_APP_RETURN_WANTED_AS_IS = 2; + + /** + * Called by an app handling the {@link #ACTION_CAPTIVE_PORTAL_SIGN_IN} + * action to indicate to the system that the captive portal has been + * dismissed. In response the framework will re-evaluate the network's + * connectivity and might take further action thereafter. + * + * @param network The {@link Network} object passed via + * {@link #EXTRA_NETWORK} with the + * {@link #ACTION_CAPTIVE_PORTAL_SIGN_IN} action. + * @param actionToken The {@code String} passed via + * {@link #EXTRA_CAPTIVE_PORTAL_TOKEN} with the + * {@code ACTION_CAPTIVE_PORTAL_SIGN_IN} action. + */ + public void reportCaptivePortalDismissed(Network network, String actionToken) { + try { + mService.captivePortalAppResponse(network, CAPTIVE_PORTAL_APP_RETURN_DISMISSED, + actionToken); + } catch (RemoteException e) { + } + } + + /** + * Called by an app handling the {@link #ACTION_CAPTIVE_PORTAL_SIGN_IN} + * action to indicate that the user does not want to pursue signing in to + * captive portal and the system should continue to prefer other networks + * without captive portals for use as the default active data network. The + * system will not retest the network for a captive portal so as to avoid + * disturbing the user with further sign in to network notifications. + * + * @param network The {@link Network} object passed via + * {@link #EXTRA_NETWORK} with the + * {@link #ACTION_CAPTIVE_PORTAL_SIGN_IN} action. + * @param actionToken The {@code String} passed via + * {@link #EXTRA_CAPTIVE_PORTAL_TOKEN} with the + * {@code ACTION_CAPTIVE_PORTAL_SIGN_IN} action. + */ + public void ignoreNetworkWithCaptivePortal(Network network, String actionToken) { + try { + mService.captivePortalAppResponse(network, CAPTIVE_PORTAL_APP_RETURN_UNWANTED, + actionToken); + } catch (RemoteException e) { + } + } + + /** + * Called by an app handling the {@link #ACTION_CAPTIVE_PORTAL_SIGN_IN} + * action to indicate the user wants to use this network as is, even though + * the captive portal is still in place. The system will treat the network + * as if it did not have a captive portal when selecting the network to use + * as the default active data network. This may result in this network + * becoming the default active data network, which could disrupt network + * connectivity for apps because the captive portal is still in place. + * + * @param network The {@link Network} object passed via + * {@link #EXTRA_NETWORK} with the + * {@link #ACTION_CAPTIVE_PORTAL_SIGN_IN} action. + * @param actionToken The {@code String} passed via + * {@link #EXTRA_CAPTIVE_PORTAL_TOKEN} with the + * {@code ACTION_CAPTIVE_PORTAL_SIGN_IN} action. + * @hide + */ + public void useNetworkWithCaptivePortal(Network network, String actionToken) { + try { + mService.captivePortalAppResponse(network, CAPTIVE_PORTAL_APP_RETURN_WANTED_AS_IS, + actionToken); + } catch (RemoteException e) { + } + } + /** * Set a network-independent global http proxy. This is not normally what you want * for typical HTTP proxies - they are general network dependent. However if you're @@ -1941,6 +2067,7 @@ public class ConnectivityManager { * @param networkType * * {@hide} + * @deprecated Doesn't properly deal with multiple connected networks of the same type. */ public void setProvisioningNotificationVisible(boolean visible, int networkType, String action) { diff --git a/core/java/android/net/IConnectivityManager.aidl b/core/java/android/net/IConnectivityManager.aidl index efc76b3..77200a5 100644 --- a/core/java/android/net/IConnectivityManager.aidl +++ b/core/java/android/net/IConnectivityManager.aidl @@ -98,6 +98,8 @@ interface IConnectivityManager void reportNetworkConnectivity(in Network network, boolean hasConnectivity); + void captivePortalAppResponse(in Network network, int response, String actionToken); + ProxyInfo getGlobalProxy(); void setGlobalProxy(in ProxyInfo p); diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml index f430eb5..018c1a1 100644 --- a/core/res/AndroidManifest.xml +++ b/core/res/AndroidManifest.xml @@ -212,6 +212,7 @@ <protected-broadcast android:name="android.intent.action.MEDIA_UNMOUNTABLE" /> <protected-broadcast android:name="android.intent.action.MEDIA_EJECT" /> + <protected-broadcast android:name="android.net.conn.CAPTIVE_PORTAL" /> <protected-broadcast android:name="android.net.conn.CONNECTIVITY_CHANGE" /> <!-- @deprecated. Only {@link android.net.ConnectivityManager.CONNECTIVITY_ACTION} is sent. --> <protected-broadcast android:name="android.net.conn.CONNECTIVITY_CHANGE_IMMEDIATE" /> diff --git a/packages/CaptivePortalLogin/AndroidManifest.xml b/packages/CaptivePortalLogin/AndroidManifest.xml index 2ec15be..aea8585 100644 --- a/packages/CaptivePortalLogin/AndroidManifest.xml +++ b/packages/CaptivePortalLogin/AndroidManifest.xml @@ -21,6 +21,7 @@ <uses-permission android:name="android.permission.INTERNET" /> <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" /> + <uses-permission android:name="android.permission.CONNECTIVITY_INTERNAL" /> <application android:label="@string/app_name" > <activity @@ -28,9 +29,8 @@ android:label="@string/action_bar_label" android:theme="@style/AppTheme" > <intent-filter> - <action android:name="android.intent.action.ACTION_SEND"/> + <action android:name="android.net.conn.CAPTIVE_PORTAL"/> <category android:name="android.intent.category.DEFAULT"/> - <data android:mimeType="text/plain"/> </intent-filter> </activity> </application> diff --git a/packages/CaptivePortalLogin/src/com/android/captiveportallogin/CaptivePortalLoginActivity.java b/packages/CaptivePortalLogin/src/com/android/captiveportallogin/CaptivePortalLoginActivity.java index e4054ac..b86fc4b 100644 --- a/packages/CaptivePortalLogin/src/com/android/captiveportallogin/CaptivePortalLoginActivity.java +++ b/packages/CaptivePortalLogin/src/com/android/captiveportallogin/CaptivePortalLoginActivity.java @@ -56,24 +56,13 @@ public class CaptivePortalLoginActivity extends Activity { private static final String DEFAULT_SERVER = "connectivitycheck.android.com"; private static final int SOCKET_TIMEOUT_MS = 10000; - // Keep this in sync with NetworkMonitor. - // Intent broadcast to ConnectivityService indicating sign-in is complete. - // Extras: - // EXTRA_TEXT = netId - // LOGGED_IN_RESULT = one of the CAPTIVE_PORTAL_APP_RETURN_* values below. - // RESPONSE_TOKEN = data fragment from launching Intent - private static final String ACTION_CAPTIVE_PORTAL_LOGGED_IN = - "android.net.netmon.captive_portal_logged_in"; - private static final String LOGGED_IN_RESULT = "result"; - private static final int CAPTIVE_PORTAL_APP_RETURN_APPEASED = 0; - private static final int CAPTIVE_PORTAL_APP_RETURN_UNWANTED = 1; - private static final int CAPTIVE_PORTAL_APP_RETURN_WANTED_AS_IS = 2; - private static final String RESPONSE_TOKEN = "response_token"; + private enum Result { DISMISSED, UNWANTED, WANTED_AS_IS }; private URL mURL; - private int mNetId; + private Network mNetwork; private String mResponseToken; private NetworkCallback mNetworkCallback; + private ConnectivityManager mCm; @Override protected void onCreate(Bundle savedInstanceState) { @@ -81,23 +70,19 @@ public class CaptivePortalLoginActivity extends Activity { String server = Settings.Global.getString(getContentResolver(), "captive_portal_server"); if (server == null) server = DEFAULT_SERVER; + mCm = ConnectivityManager.from(this); try { mURL = new URL("http", server, "/generate_204"); - final Uri dataUri = getIntent().getData(); - if (!dataUri.getScheme().equals("netid")) { - throw new MalformedURLException(); - } - mNetId = Integer.parseInt(dataUri.getSchemeSpecificPart()); - mResponseToken = dataUri.getFragment(); - } catch (MalformedURLException|NumberFormatException e) { + } catch (MalformedURLException e) { // System misconfigured, bail out in a way that at least provides network access. - done(CAPTIVE_PORTAL_APP_RETURN_WANTED_AS_IS); + Log.e(TAG, "Invalid captive portal URL, server=" + server); + done(Result.WANTED_AS_IS); } + mNetwork = getIntent().getParcelableExtra(ConnectivityManager.EXTRA_NETWORK); + mResponseToken = getIntent().getStringExtra(ConnectivityManager.EXTRA_CAPTIVE_PORTAL_TOKEN); - final ConnectivityManager cm = ConnectivityManager.from(this); - final Network network = new Network(mNetId); // Also initializes proxy system properties. - cm.bindProcessToNetwork(network); + mCm.bindProcessToNetwork(mNetwork); // Proxy system properties must be initialized before setContentView is called because // setContentView initializes the WebView logic which in turn reads the system properties. @@ -106,7 +91,7 @@ public class CaptivePortalLoginActivity extends Activity { getActionBar().setDisplayShowHomeEnabled(false); // Exit app if Network disappears. - final NetworkCapabilities networkCapabilities = cm.getNetworkCapabilities(network); + final NetworkCapabilities networkCapabilities = mCm.getNetworkCapabilities(mNetwork); if (networkCapabilities == null) { finish(); return; @@ -114,14 +99,14 @@ public class CaptivePortalLoginActivity extends Activity { mNetworkCallback = new NetworkCallback() { @Override public void onLost(Network lostNetwork) { - if (network.equals(lostNetwork)) done(CAPTIVE_PORTAL_APP_RETURN_UNWANTED); + if (mNetwork.equals(lostNetwork)) done(Result.UNWANTED); } }; final NetworkRequest.Builder builder = new NetworkRequest.Builder(); for (int transportType : networkCapabilities.getTransportTypes()) { builder.addTransportType(transportType); } - cm.registerNetworkCallback(builder.build(), mNetworkCallback); + mCm.registerNetworkCallback(builder.build(), mNetworkCallback); final WebView myWebView = (WebView) findViewById(R.id.webview); myWebView.clearCache(true); @@ -158,15 +143,21 @@ public class CaptivePortalLoginActivity extends Activity { } } - private void done(int result) { + private void done(Result result) { if (mNetworkCallback != null) { - ConnectivityManager.from(this).unregisterNetworkCallback(mNetworkCallback); + mCm.unregisterNetworkCallback(mNetworkCallback); + } + switch (result) { + case DISMISSED: + mCm.reportCaptivePortalDismissed(mNetwork, mResponseToken); + break; + case UNWANTED: + mCm.ignoreNetworkWithCaptivePortal(mNetwork, mResponseToken); + break; + case WANTED_AS_IS: + mCm.useNetworkWithCaptivePortal(mNetwork, mResponseToken); + break; } - Intent intent = new Intent(ACTION_CAPTIVE_PORTAL_LOGGED_IN); - intent.putExtra(Intent.EXTRA_TEXT, String.valueOf(mNetId)); - intent.putExtra(LOGGED_IN_RESULT, String.valueOf(result)); - intent.putExtra(RESPONSE_TOKEN, mResponseToken); - sendBroadcast(intent); finish(); } @@ -190,11 +181,11 @@ public class CaptivePortalLoginActivity extends Activity { public boolean onOptionsItemSelected(MenuItem item) { int id = item.getItemId(); if (id == R.id.action_use_network) { - done(CAPTIVE_PORTAL_APP_RETURN_WANTED_AS_IS); + done(Result.WANTED_AS_IS); return true; } if (id == R.id.action_do_not_use_network) { - done(CAPTIVE_PORTAL_APP_RETURN_UNWANTED); + done(Result.UNWANTED); return true; } return super.onOptionsItemSelected(item); @@ -223,7 +214,7 @@ public class CaptivePortalLoginActivity extends Activity { if (urlConnection != null) urlConnection.disconnect(); } if (httpResponseCode == 204) { - done(CAPTIVE_PORTAL_APP_RETURN_APPEASED); + done(Result.DISMISSED); } } }).start(); diff --git a/services/core/java/com/android/server/BluetoothManagerService.java b/services/core/java/com/android/server/BluetoothManagerService.java index 3e5eee8..ef82bb7 100644 --- a/services/core/java/com/android/server/BluetoothManagerService.java +++ b/services/core/java/com/android/server/BluetoothManagerService.java @@ -56,6 +56,7 @@ import java.io.PrintWriter; import java.util.HashMap; import java.util.Map; +import java.util.*; class BluetoothManagerService extends IBluetoothManager.Stub { private static final String TAG = "BluetoothManagerService"; private static final boolean DBG = true; diff --git a/services/core/java/com/android/server/ConnectivityService.java b/services/core/java/com/android/server/ConnectivityService.java index 7d8e9de..12a99b0 100644 --- a/services/core/java/com/android/server/ConnectivityService.java +++ b/services/core/java/com/android/server/ConnectivityService.java @@ -2608,6 +2608,16 @@ public class ConnectivityService extends IConnectivityManager.Stub } } + public void captivePortalAppResponse(Network network, int response, String actionToken) { + if (response == ConnectivityManager.CAPTIVE_PORTAL_APP_RETURN_WANTED_AS_IS) { + enforceConnectivityInternalPermission(); + } + final NetworkAgentInfo nai = getNetworkAgentInfoForNetwork(network); + if (nai == null) return; + nai.networkMonitor.sendMessage(NetworkMonitor.CMD_CAPTIVE_PORTAL_APP_FINISHED, response, 0, + actionToken); + } + public ProxyInfo getDefaultProxy() { // this information is already available as a world read/writable jvm property // so this API change wouldn't have a benifit. It also breaks the passing diff --git a/services/core/java/com/android/server/connectivity/NetworkMonitor.java b/services/core/java/com/android/server/connectivity/NetworkMonitor.java index 7e20276..4e83992 100644 --- a/services/core/java/com/android/server/connectivity/NetworkMonitor.java +++ b/services/core/java/com/android/server/connectivity/NetworkMonitor.java @@ -83,17 +83,6 @@ public class NetworkMonitor extends StateMachine { private static final String PERMISSION_ACCESS_NETWORK_CONDITIONS = "android.permission.ACCESS_NETWORK_CONDITIONS"; - // Keep these in sync with CaptivePortalLoginActivity.java. - // Intent broadcast from CaptivePortalLogin indicating sign-in is complete. - // Extras: - // EXTRA_TEXT = netId - // LOGGED_IN_RESULT = one of the CAPTIVE_PORTAL_APP_RETURN_* values below. - // RESPONSE_TOKEN = data fragment from launching Intent - private static final String ACTION_CAPTIVE_PORTAL_LOGGED_IN = - "android.net.netmon.captive_portal_logged_in"; - private static final String LOGGED_IN_RESULT = "result"; - private static final String RESPONSE_TOKEN = "response_token"; - // After a network has been tested this result can be sent with EVENT_NETWORK_TESTED. // The network should be used as a default internet connection. It was found to be: // 1. a functioning network providing internet access, or @@ -166,11 +155,12 @@ public class NetworkMonitor extends StateMachine { /** * Message to self indicating captive portal app finished. - * arg1 = one of: CAPTIVE_PORTAL_APP_RETURN_APPEASED, + * arg1 = one of: CAPTIVE_PORTAL_APP_RETURN_DISMISSED, * CAPTIVE_PORTAL_APP_RETURN_UNWANTED, * CAPTIVE_PORTAL_APP_RETURN_WANTED_AS_IS + * obj = mCaptivePortalLoggedInResponseToken as String */ - private static final int CMD_CAPTIVE_PORTAL_APP_FINISHED = BASE + 9; + public static final int CMD_CAPTIVE_PORTAL_APP_FINISHED = BASE + 9; /** * Request ConnectivityService display provisioning notification. @@ -181,26 +171,11 @@ public class NetworkMonitor extends StateMachine { public static final int EVENT_PROVISIONING_NOTIFICATION = BASE + 10; /** - * Message to self indicating sign-in app bypassed captive portal. - */ - private static final int EVENT_APP_BYPASSED_CAPTIVE_PORTAL = BASE + 11; - - /** - * Message to self indicating no sign-in app responded. + * Message to self indicating sign-in app should be launched. + * Sent by mLaunchCaptivePortalAppBroadcastReceiver when the + * user touches the sign in notification. */ - private static final int EVENT_NO_APP_RESPONSE = BASE + 12; - - /** - * Message to self indicating sign-in app indicates sign-in is not possible. - */ - private static final int EVENT_APP_INDICATES_SIGN_IN_IMPOSSIBLE = BASE + 13; - - /** - * Return codes from captive portal sign-in app. - */ - public static final int CAPTIVE_PORTAL_APP_RETURN_APPEASED = 0; - public static final int CAPTIVE_PORTAL_APP_RETURN_UNWANTED = 1; - public static final int CAPTIVE_PORTAL_APP_RETURN_WANTED_AS_IS = 2; + private static final int CMD_LAUNCH_CAPTIVE_PORTAL_APP = BASE + 11; private static final String LINGER_DELAY_PROPERTY = "persist.netmon.linger"; // Default to 30s linger time-out. @@ -255,7 +230,7 @@ public class NetworkMonitor extends StateMachine { private final State mCaptivePortalState = new CaptivePortalState(); private final State mLingeringState = new LingeringState(); - private CaptivePortalLoggedInBroadcastReceiver mCaptivePortalLoggedInBroadcastReceiver = null; + private CustomIntentReceiver mLaunchCaptivePortalAppBroadcastReceiver = null; private String mCaptivePortalLoggedInResponseToken = null; public NetworkMonitor(Context context, Handler handler, NetworkAgentInfo networkAgentInfo, @@ -319,9 +294,9 @@ public class NetworkMonitor extends StateMachine { return HANDLED; case CMD_NETWORK_DISCONNECTED: if (DBG) log("Disconnected - quitting"); - if (mCaptivePortalLoggedInBroadcastReceiver != null) { - mContext.unregisterReceiver(mCaptivePortalLoggedInBroadcastReceiver); - mCaptivePortalLoggedInBroadcastReceiver = null; + if (mLaunchCaptivePortalAppBroadcastReceiver != null) { + mContext.unregisterReceiver(mLaunchCaptivePortalAppBroadcastReceiver); + mLaunchCaptivePortalAppBroadcastReceiver = null; } quit(); return HANDLED; @@ -332,14 +307,21 @@ public class NetworkMonitor extends StateMachine { transitionTo(mEvaluatingState); return HANDLED; case CMD_CAPTIVE_PORTAL_APP_FINISHED: - // Previous token was broadcast, come up with a new one. + if (!mCaptivePortalLoggedInResponseToken.equals((String)message.obj)) + return HANDLED; + // Previous token was sent out, come up with a new one. mCaptivePortalLoggedInResponseToken = String.valueOf(new Random().nextLong()); switch (message.arg1) { - case CAPTIVE_PORTAL_APP_RETURN_APPEASED: - case CAPTIVE_PORTAL_APP_RETURN_WANTED_AS_IS: + case ConnectivityManager.CAPTIVE_PORTAL_APP_RETURN_DISMISSED: + sendMessage(CMD_FORCE_REEVALUATION, 0 /* no UID */, + 0 /* INITIAL_ATTEMPTS */); + break; + case ConnectivityManager.CAPTIVE_PORTAL_APP_RETURN_WANTED_AS_IS: + // TODO: Distinguish this from a network that actually validates. + // Displaying the "!" on the system UI icon may still be a good idea. transitionTo(mValidatedState); break; - case CAPTIVE_PORTAL_APP_RETURN_UNWANTED: + case ConnectivityManager.CAPTIVE_PORTAL_APP_RETURN_UNWANTED: mUserDoesNotWant = true; // TODO: Should teardown network. transitionTo(mOfflineState); @@ -417,6 +399,25 @@ public class NetworkMonitor extends StateMachine { // is required. This State takes care to clear the notification upon exit from the State. private class MaybeNotifyState extends State { @Override + public boolean processMessage(Message message) { + if (DBG) log(getName() + message.toString()); + switch (message.what) { + case CMD_LAUNCH_CAPTIVE_PORTAL_APP: + final Intent intent = new Intent( + ConnectivityManager.ACTION_CAPTIVE_PORTAL_SIGN_IN); + intent.putExtra(ConnectivityManager.EXTRA_NETWORK, mNetworkAgentInfo.network); + intent.putExtra(ConnectivityManager.EXTRA_CAPTIVE_PORTAL_TOKEN, + mCaptivePortalLoggedInResponseToken); + intent.setFlags( + Intent.FLAG_ACTIVITY_BROUGHT_TO_FRONT | Intent.FLAG_ACTIVITY_NEW_TASK); + mContext.startActivityAsUser(intent, UserHandle.CURRENT); + return HANDLED; + default: + return NOT_HANDLED; + } + } + + @Override public void exit() { Message message = obtainMessage(EVENT_PROVISIONING_NOTIFICATION, 0, mNetworkAgentInfo.network.netId, null); @@ -512,7 +513,9 @@ public class NetworkMonitor extends StateMachine { mContext.registerReceiver(this, new IntentFilter(mAction)); } public PendingIntent getPendingIntent() { - return PendingIntent.getBroadcast(mContext, 0, new Intent(mAction), 0); + final Intent intent = new Intent(mAction); + intent.setPackage(mContext.getPackageName()); + return PendingIntent.getBroadcast(mContext, 0, intent, 0); } @Override public void onReceive(Context context, Intent intent) { @@ -520,48 +523,29 @@ public class NetworkMonitor extends StateMachine { } } - private class CaptivePortalLoggedInBroadcastReceiver extends BroadcastReceiver { - @Override - public void onReceive(Context context, Intent intent) { - if (Integer.parseInt(intent.getStringExtra(Intent.EXTRA_TEXT)) == - mNetworkAgentInfo.network.netId && - mCaptivePortalLoggedInResponseToken.equals( - intent.getStringExtra(RESPONSE_TOKEN))) { - sendMessage(obtainMessage(CMD_CAPTIVE_PORTAL_APP_FINISHED, - Integer.parseInt(intent.getStringExtra(LOGGED_IN_RESULT)), 0)); - } - } - } - // Being in the CaptivePortalState State indicates a captive portal was detected and the user // has been shown a notification to sign-in. private class CaptivePortalState extends State { + private static final String ACTION_LAUNCH_CAPTIVE_PORTAL_APP = + "android.net.netmon.launchCaptivePortalApp"; + @Override public void enter() { mConnectivityServiceHandler.sendMessage(obtainMessage(EVENT_NETWORK_TESTED, NETWORK_TEST_RESULT_INVALID, 0, mNetworkAgentInfo)); - - // Assemble Intent to launch captive portal sign-in app. - final Intent intent = new Intent(Intent.ACTION_SEND); - // Intent cannot use extras because PendingIntent.getActivity will merge matching - // Intents erasing extras. Use data instead of extras to encode NetID. - intent.setData(Uri.fromParts("netid", Integer.toString(mNetworkAgentInfo.network.netId), - mCaptivePortalLoggedInResponseToken)); - intent.setComponent(new ComponentName("com.android.captiveportallogin", - "com.android.captiveportallogin.CaptivePortalLoginActivity")); - intent.setFlags(Intent.FLAG_ACTIVITY_BROUGHT_TO_FRONT | Intent.FLAG_ACTIVITY_NEW_TASK); - - if (mCaptivePortalLoggedInBroadcastReceiver == null) { + // Create a CustomIntentReceiver that sends us a + // CMD_LAUNCH_CAPTIVE_PORTAL_APP message when the user + // touches the notification. + if (mLaunchCaptivePortalAppBroadcastReceiver == null) { // Wait for result. - mCaptivePortalLoggedInBroadcastReceiver = - new CaptivePortalLoggedInBroadcastReceiver(); - final IntentFilter filter = new IntentFilter(ACTION_CAPTIVE_PORTAL_LOGGED_IN); - mContext.registerReceiver(mCaptivePortalLoggedInBroadcastReceiver, filter); + mLaunchCaptivePortalAppBroadcastReceiver = new CustomIntentReceiver( + ACTION_LAUNCH_CAPTIVE_PORTAL_APP, new Random().nextInt(), + CMD_LAUNCH_CAPTIVE_PORTAL_APP); } - // Initiate notification to sign-in. + // Display the sign in notification. Message message = obtainMessage(EVENT_PROVISIONING_NOTIFICATION, 1, mNetworkAgentInfo.network.netId, - PendingIntent.getActivity(mContext, 0, intent, 0)); + mLaunchCaptivePortalAppBroadcastReceiver.getPendingIntent()); mConnectivityServiceHandler.sendMessage(message); } diff --git a/services/net/java/android/net/dhcp/DhcpAckPacket.java b/services/net/java/android/net/dhcp/DhcpAckPacket.java index 25b8093..c0e1d19 100644 --- a/services/net/java/android/net/dhcp/DhcpAckPacket.java +++ b/services/net/java/android/net/dhcp/DhcpAckPacket.java @@ -29,9 +29,9 @@ class DhcpAckPacket extends DhcpPacket { */ private final Inet4Address mSrcIp; - DhcpAckPacket(int transId, boolean broadcast, Inet4Address serverAddress, + DhcpAckPacket(int transId, short secs, boolean broadcast, Inet4Address serverAddress, Inet4Address clientIp, byte[] clientMac) { - super(transId, INADDR_ANY, clientIp, serverAddress, INADDR_ANY, clientMac, broadcast); + super(transId, secs, INADDR_ANY, clientIp, serverAddress, INADDR_ANY, clientMac, broadcast); mBroadcast = broadcast; mSrcIp = serverAddress; } diff --git a/services/net/java/android/net/dhcp/DhcpClient.java b/services/net/java/android/net/dhcp/DhcpClient.java index ab56493..e1d1787 100644 --- a/services/net/java/android/net/dhcp/DhcpClient.java +++ b/services/net/java/android/net/dhcp/DhcpClient.java @@ -154,6 +154,7 @@ public class DhcpClient extends BaseDhcpStateMachine { private byte[] mHwAddr; private PacketSocketAddress mInterfaceBroadcastAddr; private int mTransactionId; + private long mTransactionStartMillis; private DhcpResults mDhcpLease; private long mDhcpLeaseExpiry; private DhcpResults mOffer; @@ -264,8 +265,9 @@ public class DhcpClient extends BaseDhcpStateMachine { } } - private void initTransactionId() { + private void startNewTransaction() { mTransactionId = mRandom.nextInt(); + mTransactionStartMillis = SystemClock.elapsedRealtime(); } private boolean initSockets() { @@ -344,6 +346,10 @@ public class DhcpClient extends BaseDhcpStateMachine { } } + private short getSecs() { + return (short) ((SystemClock.elapsedRealtime() - mTransactionStartMillis) / 1000); + } + private boolean transmitPacket(ByteBuffer buf, String description, Inet4Address to) { try { if (to.equals(INADDR_BROADCAST)) { @@ -362,7 +368,8 @@ public class DhcpClient extends BaseDhcpStateMachine { private boolean sendDiscoverPacket() { ByteBuffer packet = DhcpPacket.buildDiscoverPacket( - DhcpPacket.ENCAP_L2, mTransactionId, mHwAddr, DO_UNICAST, REQUESTED_PARAMS); + DhcpPacket.ENCAP_L2, mTransactionId, getSecs(), mHwAddr, + DO_UNICAST, REQUESTED_PARAMS); return transmitPacket(packet, "DHCPDISCOVER", INADDR_BROADCAST); } @@ -373,7 +380,7 @@ public class DhcpClient extends BaseDhcpStateMachine { int encap = to.equals(INADDR_BROADCAST) ? DhcpPacket.ENCAP_L2 : DhcpPacket.ENCAP_BOOTP; ByteBuffer packet = DhcpPacket.buildRequestPacket( - encap, mTransactionId, clientAddress, + encap, mTransactionId, getSecs(), clientAddress, DO_UNICAST, mHwAddr, requestedAddress, serverAddress, REQUESTED_PARAMS, null); String description = "DHCPREQUEST ciaddr=" + clientAddress.getHostAddress() + @@ -669,7 +676,7 @@ public class DhcpClient extends BaseDhcpStateMachine { @Override public void enter() { super.enter(); - initTransactionId(); + startNewTransaction(); } protected boolean sendPacket() { @@ -776,7 +783,7 @@ public class DhcpClient extends BaseDhcpStateMachine { @Override public void enter() { super.enter(); - initTransactionId(); + startNewTransaction(); } protected boolean sendPacket() { diff --git a/services/net/java/android/net/dhcp/DhcpDeclinePacket.java b/services/net/java/android/net/dhcp/DhcpDeclinePacket.java index 4a22b65..7ecdea7 100644 --- a/services/net/java/android/net/dhcp/DhcpDeclinePacket.java +++ b/services/net/java/android/net/dhcp/DhcpDeclinePacket.java @@ -26,10 +26,10 @@ class DhcpDeclinePacket extends DhcpPacket { /** * Generates a DECLINE packet with the specified parameters. */ - DhcpDeclinePacket(int transId, Inet4Address clientIp, Inet4Address yourIp, + DhcpDeclinePacket(int transId, short secs, Inet4Address clientIp, Inet4Address yourIp, Inet4Address nextIp, Inet4Address relayIp, byte[] clientMac) { - super(transId, clientIp, yourIp, nextIp, relayIp, clientMac, false); + super(transId, secs, clientIp, yourIp, nextIp, relayIp, clientMac, false); } public String toString() { diff --git a/services/net/java/android/net/dhcp/DhcpDiscoverPacket.java b/services/net/java/android/net/dhcp/DhcpDiscoverPacket.java index ed0fdc6..91e6bd6 100644 --- a/services/net/java/android/net/dhcp/DhcpDiscoverPacket.java +++ b/services/net/java/android/net/dhcp/DhcpDiscoverPacket.java @@ -26,8 +26,8 @@ class DhcpDiscoverPacket extends DhcpPacket { /** * Generates a DISCOVER packet with the specified parameters. */ - DhcpDiscoverPacket(int transId, byte[] clientMac, boolean broadcast) { - super(transId, INADDR_ANY, INADDR_ANY, INADDR_ANY, INADDR_ANY, clientMac, broadcast); + DhcpDiscoverPacket(int transId, short secs, byte[] clientMac, boolean broadcast) { + super(transId, secs, INADDR_ANY, INADDR_ANY, INADDR_ANY, INADDR_ANY, clientMac, broadcast); } public String toString() { diff --git a/services/net/java/android/net/dhcp/DhcpInformPacket.java b/services/net/java/android/net/dhcp/DhcpInformPacket.java index 2434fc9..7a83466 100644 --- a/services/net/java/android/net/dhcp/DhcpInformPacket.java +++ b/services/net/java/android/net/dhcp/DhcpInformPacket.java @@ -26,10 +26,10 @@ class DhcpInformPacket extends DhcpPacket { /** * Generates an INFORM packet with the specified parameters. */ - DhcpInformPacket(int transId, Inet4Address clientIp, Inet4Address yourIp, + DhcpInformPacket(int transId, short secs, Inet4Address clientIp, Inet4Address yourIp, Inet4Address nextIp, Inet4Address relayIp, byte[] clientMac) { - super(transId, clientIp, yourIp, nextIp, relayIp, clientMac, false); + super(transId, secs, clientIp, yourIp, nextIp, relayIp, clientMac, false); } public String toString() { diff --git a/services/net/java/android/net/dhcp/DhcpNakPacket.java b/services/net/java/android/net/dhcp/DhcpNakPacket.java index 1390ea7..6458232 100644 --- a/services/net/java/android/net/dhcp/DhcpNakPacket.java +++ b/services/net/java/android/net/dhcp/DhcpNakPacket.java @@ -26,10 +26,10 @@ class DhcpNakPacket extends DhcpPacket { /** * Generates a NAK packet with the specified parameters. */ - DhcpNakPacket(int transId, Inet4Address clientIp, Inet4Address yourIp, + DhcpNakPacket(int transId, short secs, Inet4Address clientIp, Inet4Address yourIp, Inet4Address nextIp, Inet4Address relayIp, byte[] clientMac) { - super(transId, INADDR_ANY, INADDR_ANY, nextIp, relayIp, + super(transId, secs, INADDR_ANY, INADDR_ANY, nextIp, relayIp, clientMac, false); } diff --git a/services/net/java/android/net/dhcp/DhcpOfferPacket.java b/services/net/java/android/net/dhcp/DhcpOfferPacket.java index b1f3bbd..af41708 100644 --- a/services/net/java/android/net/dhcp/DhcpOfferPacket.java +++ b/services/net/java/android/net/dhcp/DhcpOfferPacket.java @@ -31,9 +31,9 @@ class DhcpOfferPacket extends DhcpPacket { /** * Generates a OFFER packet with the specified parameters. */ - DhcpOfferPacket(int transId, boolean broadcast, Inet4Address serverAddress, + DhcpOfferPacket(int transId, short secs, boolean broadcast, Inet4Address serverAddress, Inet4Address clientIp, byte[] clientMac) { - super(transId, INADDR_ANY, clientIp, INADDR_ANY, INADDR_ANY, clientMac, broadcast); + super(transId, secs, INADDR_ANY, clientIp, INADDR_ANY, INADDR_ANY, clientMac, broadcast); mSrcIp = serverAddress; } diff --git a/services/net/java/android/net/dhcp/DhcpPacket.java b/services/net/java/android/net/dhcp/DhcpPacket.java index a64ee6f..b923b1b 100644 --- a/services/net/java/android/net/dhcp/DhcpPacket.java +++ b/services/net/java/android/net/dhcp/DhcpPacket.java @@ -226,6 +226,11 @@ abstract class DhcpPacket { protected final int mTransId; /** + * The seconds field in the BOOTP header. Per RFC, should be nonzero in client requests only. + */ + protected final short mSecs; + + /** * The IP address of the client host. This address is typically * proposed by the client (from an earlier DHCP negotiation) or * supplied by the server. @@ -258,10 +263,11 @@ abstract class DhcpPacket { */ abstract void finishPacket(ByteBuffer buffer); - protected DhcpPacket(int transId, Inet4Address clientIp, Inet4Address yourIp, + protected DhcpPacket(int transId, short secs, Inet4Address clientIp, Inet4Address yourIp, Inet4Address nextIp, Inet4Address relayIp, byte[] clientMac, boolean broadcast) { mTransId = transId; + mSecs = secs; mClientIp = clientIp; mYourIp = yourIp; mNextIp = nextIp; @@ -357,7 +363,7 @@ abstract class DhcpPacket { buf.put((byte) mClientMac.length); // Hardware Address Length buf.put((byte) 0); // Hop Count buf.putInt(mTransId); // Transaction ID - buf.putShort((short) 0); // Elapsed Seconds + buf.putShort(mSecs); // Elapsed Seconds if (broadcast) { buf.putShort((short) 0x8000); // Flags @@ -652,6 +658,7 @@ abstract class DhcpPacket { { // bootp parameters int transactionId; + short secs; Inet4Address clientIp; Inet4Address yourIp; Inet4Address nextIp; @@ -759,7 +766,7 @@ abstract class DhcpPacket { byte addrLen = packet.get(); byte hops = packet.get(); transactionId = packet.getInt(); - short elapsed = packet.getShort(); + secs = packet.getShort(); short bootpFlags = packet.getShort(); boolean broadcast = (bootpFlags & 0x8000) != 0; byte[] ipv4addr = new byte[4]; @@ -902,33 +909,33 @@ abstract class DhcpPacket { case -1: return null; case DHCP_MESSAGE_TYPE_DISCOVER: newPacket = new DhcpDiscoverPacket( - transactionId, clientMac, broadcast); + transactionId, secs, clientMac, broadcast); break; case DHCP_MESSAGE_TYPE_OFFER: newPacket = new DhcpOfferPacket( - transactionId, broadcast, ipSrc, yourIp, clientMac); + transactionId, secs, broadcast, ipSrc, yourIp, clientMac); break; case DHCP_MESSAGE_TYPE_REQUEST: newPacket = new DhcpRequestPacket( - transactionId, clientIp, clientMac, broadcast); + transactionId, secs, clientIp, clientMac, broadcast); break; case DHCP_MESSAGE_TYPE_DECLINE: newPacket = new DhcpDeclinePacket( - transactionId, clientIp, yourIp, nextIp, relayIp, + transactionId, secs, clientIp, yourIp, nextIp, relayIp, clientMac); break; case DHCP_MESSAGE_TYPE_ACK: newPacket = new DhcpAckPacket( - transactionId, broadcast, ipSrc, yourIp, clientMac); + transactionId, secs, broadcast, ipSrc, yourIp, clientMac); break; case DHCP_MESSAGE_TYPE_NAK: newPacket = new DhcpNakPacket( - transactionId, clientIp, yourIp, nextIp, relayIp, + transactionId, secs, clientIp, yourIp, nextIp, relayIp, clientMac); break; case DHCP_MESSAGE_TYPE_INFORM: newPacket = new DhcpInformPacket( - transactionId, clientIp, yourIp, nextIp, relayIp, + transactionId, secs, clientIp, yourIp, nextIp, relayIp, clientMac); break; default: @@ -1008,9 +1015,9 @@ abstract class DhcpPacket { * parameters. */ public static ByteBuffer buildDiscoverPacket(int encap, int transactionId, - byte[] clientMac, boolean broadcast, byte[] expectedParams) { + short secs, byte[] clientMac, boolean broadcast, byte[] expectedParams) { DhcpPacket pkt = new DhcpDiscoverPacket( - transactionId, clientMac, broadcast); + transactionId, secs, clientMac, broadcast); pkt.mRequestedParams = expectedParams; return pkt.buildPacket(encap, DHCP_SERVER, DHCP_CLIENT); } @@ -1025,7 +1032,7 @@ abstract class DhcpPacket { Inet4Address gateway, List<Inet4Address> dnsServers, Inet4Address dhcpServerIdentifier, String domainName) { DhcpPacket pkt = new DhcpOfferPacket( - transactionId, broadcast, serverIpAddr, clientIpAddr, mac); + transactionId, (short) 0, broadcast, serverIpAddr, clientIpAddr, mac); pkt.mGateway = gateway; pkt.mDnsServers = dnsServers; pkt.mLeaseTime = timeout; @@ -1045,7 +1052,7 @@ abstract class DhcpPacket { Inet4Address gateway, List<Inet4Address> dnsServers, Inet4Address dhcpServerIdentifier, String domainName) { DhcpPacket pkt = new DhcpAckPacket( - transactionId, broadcast, serverIpAddr, clientIpAddr, mac); + transactionId, (short) 0, broadcast, serverIpAddr, clientIpAddr, mac); pkt.mGateway = gateway; pkt.mDnsServers = dnsServers; pkt.mLeaseTime = timeout; @@ -1061,7 +1068,7 @@ abstract class DhcpPacket { */ public static ByteBuffer buildNakPacket(int encap, int transactionId, Inet4Address serverIpAddr, Inet4Address clientIpAddr, byte[] mac) { - DhcpPacket pkt = new DhcpNakPacket(transactionId, clientIpAddr, + DhcpPacket pkt = new DhcpNakPacket(transactionId, (short) 0, clientIpAddr, serverIpAddr, serverIpAddr, serverIpAddr, mac); pkt.mMessage = "requested address not available"; pkt.mRequestedIp = clientIpAddr; @@ -1072,10 +1079,10 @@ abstract class DhcpPacket { * Builds a DHCP-REQUEST packet from the required specified parameters. */ public static ByteBuffer buildRequestPacket(int encap, - int transactionId, Inet4Address clientIp, boolean broadcast, + int transactionId, short secs, Inet4Address clientIp, boolean broadcast, byte[] clientMac, Inet4Address requestedIpAddress, Inet4Address serverIdentifier, byte[] requestedParams, String hostName) { - DhcpPacket pkt = new DhcpRequestPacket(transactionId, clientIp, + DhcpPacket pkt = new DhcpRequestPacket(transactionId, secs, clientIp, clientMac, broadcast); pkt.mRequestedIp = requestedIpAddress; pkt.mServerIdentifier = serverIdentifier; diff --git a/services/net/java/android/net/dhcp/DhcpRequestPacket.java b/services/net/java/android/net/dhcp/DhcpRequestPacket.java index 5d378b8..4f9aa01 100644 --- a/services/net/java/android/net/dhcp/DhcpRequestPacket.java +++ b/services/net/java/android/net/dhcp/DhcpRequestPacket.java @@ -28,9 +28,9 @@ class DhcpRequestPacket extends DhcpPacket { /** * Generates a REQUEST packet with the specified parameters. */ - DhcpRequestPacket(int transId, Inet4Address clientIp, byte[] clientMac, + DhcpRequestPacket(int transId, short secs, Inet4Address clientIp, byte[] clientMac, boolean broadcast) { - super(transId, clientIp, INADDR_ANY, INADDR_ANY, INADDR_ANY, clientMac, broadcast); + super(transId, secs, clientIp, INADDR_ANY, INADDR_ANY, INADDR_ANY, clientMac, broadcast); } public String toString() { diff --git a/services/tests/servicestests/src/android/net/dhcp/DhcpPacketTest.java b/services/tests/servicestests/src/android/net/dhcp/DhcpPacketTest.java index 2658937..4f7c7ec 100644 --- a/services/tests/servicestests/src/android/net/dhcp/DhcpPacketTest.java +++ b/services/tests/servicestests/src/android/net/dhcp/DhcpPacketTest.java @@ -41,7 +41,8 @@ public class DhcpPacketTest extends TestCase { private byte[] mDomainBytes, mVendorInfoBytes; public TestDhcpPacket(byte type, byte[] domainBytes, byte[] vendorInfoBytes) { - super(0xdeadbeef, INADDR_ANY, CLIENT_ADDR, INADDR_ANY, INADDR_ANY, CLIENT_MAC, true); + super(0xdeadbeef, (short) 0, INADDR_ANY, CLIENT_ADDR, INADDR_ANY, INADDR_ANY, + CLIENT_MAC, true); mType = type; mDomainBytes = domainBytes; mVendorInfoBytes = vendorInfoBytes; diff --git a/telecomm/java/android/telecom/Call.java b/telecomm/java/android/telecom/Call.java index 2a30384..d92c0c7 100644 --- a/telecomm/java/android/telecom/Call.java +++ b/telecomm/java/android/telecom/Call.java @@ -933,7 +933,8 @@ public final class Call { Collections.unmodifiableList(parcelableCall.getCannedSmsResponses()); } - boolean videoCallChanged = !Objects.equals(mVideoCall, parcelableCall.getVideoCall()); + boolean videoCallChanged = parcelableCall.isVideoCallProviderChanged() && + !Objects.equals(mVideoCall, parcelableCall.getVideoCall()); if (videoCallChanged) { mVideoCall = parcelableCall.getVideoCall(); } diff --git a/telecomm/java/android/telecom/Conference.java b/telecomm/java/android/telecom/Conference.java index bab60fe..0424548 100644 --- a/telecomm/java/android/telecom/Conference.java +++ b/telecomm/java/android/telecom/Conference.java @@ -50,6 +50,7 @@ public abstract class Conference implements Conferenceable { Conference conference, int connectionCapabilities) {} public void onVideoStateChanged(Conference c, int videoState) { } public void onVideoProviderChanged(Conference c, Connection.VideoProvider videoProvider) {} + public void onStatusHintsChanged(Conference conference, StatusHints statusHints) {} } private final Set<Listener> mListeners = new CopyOnWriteArraySet<>(); @@ -67,6 +68,7 @@ public abstract class Conference implements Conferenceable { private int mConnectionCapabilities; private String mDisconnectMessage; private long mConnectTimeMillis = CONNECT_TIME_NOT_SPECIFIED; + private StatusHints mStatusHints; private final Connection.Listener mConnectionDeathListener = new Connection.Listener() { @Override @@ -535,4 +537,23 @@ public abstract class Conference implements Conferenceable { getVideoProvider(), super.toString()); } + + /** + * Sets the label and icon status to display in the InCall UI. + * + * @param statusHints The status label and icon to set. + */ + public final void setStatusHints(StatusHints statusHints) { + mStatusHints = statusHints; + for (Listener l : mListeners) { + l.onStatusHintsChanged(this, statusHints); + } + } + + /** + * @return The status hints for this conference. + */ + public final StatusHints getStatusHints() { + return mStatusHints; + } } diff --git a/telecomm/java/android/telecom/Connection.java b/telecomm/java/android/telecom/Connection.java index e79584f..cd10050 100644 --- a/telecomm/java/android/telecom/Connection.java +++ b/telecomm/java/android/telecom/Connection.java @@ -28,6 +28,7 @@ import android.view.Surface; import java.util.ArrayList; import java.util.Collections; +import java.util.HashMap; import java.util.List; import java.util.Set; import java.util.concurrent.ConcurrentHashMap; @@ -402,7 +403,7 @@ public abstract class Connection implements Conferenceable { */ public static final int SESSION_MODIFY_REQUEST_REJECTED_BY_REMOTE = 5; - private static final int MSG_SET_VIDEO_CALLBACK = 1; + private static final int MSG_ADD_VIDEO_CALLBACK = 1; private static final int MSG_SET_CAMERA = 2; private static final int MSG_SET_PREVIEW_SURFACE = 3; private static final int MSG_SET_DISPLAY_SURFACE = 4; @@ -413,11 +414,16 @@ public abstract class Connection implements Conferenceable { private static final int MSG_REQUEST_CAMERA_CAPABILITIES = 9; private static final int MSG_REQUEST_CONNECTION_DATA_USAGE = 10; private static final int MSG_SET_PAUSE_IMAGE = 11; + private static final int MSG_REMOVE_VIDEO_CALLBACK = 12; private final VideoProvider.VideoProviderHandler mMessageHandler = new VideoProvider.VideoProviderHandler(); private final VideoProvider.VideoProviderBinder mBinder; - private IVideoCallback mVideoCallback; + + /** + * Stores a list of the video callbacks, keyed by IBinder. + */ + private HashMap<IBinder, IVideoCallback> mVideoCallbacks = new HashMap<>(); /** * Default handler used to consolidate binder method calls onto a single thread. @@ -426,9 +432,29 @@ public abstract class Connection implements Conferenceable { @Override public void handleMessage(Message msg) { switch (msg.what) { - case MSG_SET_VIDEO_CALLBACK: - mVideoCallback = IVideoCallback.Stub.asInterface((IBinder) msg.obj); + case MSG_ADD_VIDEO_CALLBACK: { + IBinder binder = (IBinder) msg.obj; + IVideoCallback callback = IVideoCallback.Stub + .asInterface((IBinder) msg.obj); + if (mVideoCallbacks.containsKey(binder)) { + Log.i(this, "addVideoProvider - skipped; already present."); + break; + } + mVideoCallbacks.put(binder, callback); + Log.i(this, "addVideoProvider "+ mVideoCallbacks.size()); + break; + } + case MSG_REMOVE_VIDEO_CALLBACK: { + IBinder binder = (IBinder) msg.obj; + IVideoCallback callback = IVideoCallback.Stub + .asInterface((IBinder) msg.obj); + if (!mVideoCallbacks.containsKey(binder)) { + Log.i(this, "removeVideoProvider - skipped; not present."); + break; + } + mVideoCallbacks.remove(binder); break; + } case MSG_SET_CAMERA: onSetCamera((String) msg.obj); break; @@ -469,9 +495,14 @@ public abstract class Connection implements Conferenceable { * IVideoProvider stub implementation. */ private final class VideoProviderBinder extends IVideoProvider.Stub { - public void setVideoCallback(IBinder videoCallbackBinder) { + public void addVideoCallback(IBinder videoCallbackBinder) { + mMessageHandler.obtainMessage( + MSG_ADD_VIDEO_CALLBACK, videoCallbackBinder).sendToTarget(); + } + + public void removeVideoCallback(IBinder videoCallbackBinder) { mMessageHandler.obtainMessage( - MSG_SET_VIDEO_CALLBACK, videoCallbackBinder).sendToTarget(); + MSG_REMOVE_VIDEO_CALLBACK, videoCallbackBinder).sendToTarget(); } public void setCamera(String cameraId) { @@ -609,21 +640,23 @@ public abstract class Connection implements Conferenceable { public abstract void onSetPauseImage(String uri); /** - * Invokes callback method defined in In-Call UI. + * Invokes callback method defined in listening {@link InCallService} implementations. * * @param videoProfile The requested video connection profile. */ public void receiveSessionModifyRequest(VideoProfile videoProfile) { - if (mVideoCallback != null) { + if (mVideoCallbacks != null) { try { - mVideoCallback.receiveSessionModifyRequest(videoProfile); + for (IVideoCallback callback : mVideoCallbacks.values()) { + callback.receiveSessionModifyRequest(videoProfile); + } } catch (RemoteException ignored) { } } } /** - * Invokes callback method defined in In-Call UI. + * Invokes callback method defined in listening {@link InCallService} implementations. * * @param status Status of the session modify request. Valid values are * {@link VideoProvider#SESSION_MODIFY_REQUEST_SUCCESS}, @@ -634,17 +667,19 @@ public abstract class Connection implements Conferenceable { */ public void receiveSessionModifyResponse(int status, VideoProfile requestedProfile, VideoProfile responseProfile) { - if (mVideoCallback != null) { + if (mVideoCallbacks != null) { try { - mVideoCallback.receiveSessionModifyResponse( - status, requestedProfile, responseProfile); + for (IVideoCallback callback : mVideoCallbacks.values()) { + callback.receiveSessionModifyResponse(status, requestedProfile, + responseProfile); + } } catch (RemoteException ignored) { } } } /** - * Invokes callback method defined in In-Call UI. + * Invokes callback method defined in listening {@link InCallService} implementations. * * Valid values are: {@link VideoProvider#SESSION_EVENT_RX_PAUSE}, * {@link VideoProvider#SESSION_EVENT_RX_RESUME}, @@ -654,66 +689,76 @@ public abstract class Connection implements Conferenceable { * @param event The event. */ public void handleCallSessionEvent(int event) { - if (mVideoCallback != null) { + if (mVideoCallbacks != null) { try { - mVideoCallback.handleCallSessionEvent(event); + for (IVideoCallback callback : mVideoCallbacks.values()) { + callback.handleCallSessionEvent(event); + } } catch (RemoteException ignored) { } } } /** - * Invokes callback method defined in In-Call UI. + * Invokes callback method defined in listening {@link InCallService} implementations. * * @param width The updated peer video width. * @param height The updated peer video height. */ public void changePeerDimensions(int width, int height) { - if (mVideoCallback != null) { + if (mVideoCallbacks != null) { try { - mVideoCallback.changePeerDimensions(width, height); + for (IVideoCallback callback : mVideoCallbacks.values()) { + callback.changePeerDimensions(width, height); + } } catch (RemoteException ignored) { } } } /** - * Invokes callback method defined in In-Call UI. + * Invokes callback method defined in listening {@link InCallService} implementations. * * @param dataUsage The updated data usage. */ public void changeCallDataUsage(long dataUsage) { - if (mVideoCallback != null) { + if (mVideoCallbacks != null) { try { - mVideoCallback.changeCallDataUsage(dataUsage); + for (IVideoCallback callback : mVideoCallbacks.values()) { + callback.changeCallDataUsage(dataUsage); + } } catch (RemoteException ignored) { } } } /** - * Invokes callback method defined in In-Call UI. + * Invokes callback method defined in listening {@link InCallService} implementations. * * @param cameraCapabilities The changed camera capabilities. */ public void changeCameraCapabilities(CameraCapabilities cameraCapabilities) { - if (mVideoCallback != null) { + if (mVideoCallbacks != null) { try { - mVideoCallback.changeCameraCapabilities(cameraCapabilities); + for (IVideoCallback callback : mVideoCallbacks.values()) { + callback.changeCameraCapabilities(cameraCapabilities); + } } catch (RemoteException ignored) { } } } /** - * Invokes callback method defined in In-Call UI. + * Invokes callback method defined in listening {@link InCallService} implementations. * * @param videoQuality The updated video quality. */ public void changeVideoQuality(int videoQuality) { - if (mVideoCallback != null) { + if (mVideoCallbacks != null) { try { - mVideoCallback.changeVideoQuality(videoQuality); + for (IVideoCallback callback : mVideoCallbacks.values()) { + callback.changeVideoQuality(videoQuality); + } } catch (RemoteException ignored) { } } diff --git a/telecomm/java/android/telecom/ConnectionService.java b/telecomm/java/android/telecom/ConnectionService.java index 9812815..c039acf 100644 --- a/telecomm/java/android/telecom/ConnectionService.java +++ b/telecomm/java/android/telecom/ConnectionService.java @@ -427,6 +427,12 @@ public abstract class ConnectionService extends Service { videoProvider); mAdapter.setVideoProvider(id, videoProvider); } + + @Override + public void onStatusHintsChanged(Conference conference, StatusHints statusHints) { + String id = mIdByConference.get(conference); + mAdapter.setStatusHints(id, statusHints); + } }; private final Connection.Listener mConnectionListener = new Connection.Listener() { @@ -903,8 +909,9 @@ public abstract class ConnectionService extends Service { conference.getVideoProvider() == null ? null : conference.getVideoProvider().getInterface(), conference.getVideoState(), - conference.getConnectTimeMillis() - ); + conference.getConnectTimeMillis(), + conference.getStatusHints()); + mAdapter.addConferenceCall(id, parcelableConference); mAdapter.setVideoProvider(id, conference.getVideoProvider()); mAdapter.setVideoState(id, conference.getVideoState()); diff --git a/telecomm/java/android/telecom/InCallService.java b/telecomm/java/android/telecom/InCallService.java index 7cbc0fc..e5d6ae0 100644 --- a/telecomm/java/android/telecom/InCallService.java +++ b/telecomm/java/android/telecom/InCallService.java @@ -370,6 +370,11 @@ public abstract class InCallService extends Service { public abstract void registerCallback(VideoCall.Callback callback); /** + * Clears the video call listener set via {@link #setVideoCallListener(Listener)}. + */ + public abstract void unregisterCallback(); + + /** * Sets the camera to be used for video recording in a video call. * * @param cameraId The id of the camera. diff --git a/telecomm/java/android/telecom/ParcelableCall.java b/telecomm/java/android/telecom/ParcelableCall.java index c5c3d11..1a30910 100644 --- a/telecomm/java/android/telecom/ParcelableCall.java +++ b/telecomm/java/android/telecom/ParcelableCall.java @@ -46,6 +46,7 @@ public final class ParcelableCall implements Parcelable { private final int mCallerDisplayNamePresentation; private final GatewayInfo mGatewayInfo; private final PhoneAccountHandle mAccountHandle; + private final boolean mIsVideoCallProviderChanged; private final IVideoProvider mVideoCallProvider; private InCallService.VideoCall mVideoCall; private final String mParentCallId; @@ -69,6 +70,7 @@ public final class ParcelableCall implements Parcelable { int callerDisplayNamePresentation, GatewayInfo gatewayInfo, PhoneAccountHandle accountHandle, + boolean isVideoCallProviderChanged, IVideoProvider videoCallProvider, String parentCallId, List<String> childCallIds, @@ -89,6 +91,7 @@ public final class ParcelableCall implements Parcelable { mCallerDisplayNamePresentation = callerDisplayNamePresentation; mGatewayInfo = gatewayInfo; mAccountHandle = accountHandle; + mIsVideoCallProviderChanged = isVideoCallProviderChanged; mVideoCallProvider = videoCallProvider; mParentCallId = parentCallId; mChildCallIds = childCallIds; @@ -232,6 +235,18 @@ public final class ParcelableCall implements Parcelable { return mExtras; } + /** + * Indicates to the receiver of the {@link ParcelableCall} whether a change has occurred in the + * {@link android.telecom.InCallService.VideoCall} associated with this call. Since + * {@link #getVideoCall()} creates a new {@link VideoCallImpl}, it is useful to know whether + * the provider has changed (which can influence whether it is accessed). + * + * @return {@code true} if the video call changed, {@code false} otherwise. + */ + public boolean isVideoCallProviderChanged() { + return mIsVideoCallProviderChanged; + } + /** Responsible for creating ParcelableCall objects for deserialized Parcels. */ public static final Parcelable.Creator<ParcelableCall> CREATOR = new Parcelable.Creator<ParcelableCall> () { @@ -252,6 +267,7 @@ public final class ParcelableCall implements Parcelable { int callerDisplayNamePresentation = source.readInt(); GatewayInfo gatewayInfo = source.readParcelable(classLoader); PhoneAccountHandle accountHandle = source.readParcelable(classLoader); + boolean isVideoCallProviderChanged = source.readByte() == 1; IVideoProvider videoCallProvider = IVideoProvider.Stub.asInterface(source.readStrongBinder()); String parentCallId = source.readString(); @@ -276,6 +292,7 @@ public final class ParcelableCall implements Parcelable { callerDisplayNamePresentation, gatewayInfo, accountHandle, + isVideoCallProviderChanged, videoCallProvider, parentCallId, childCallIds, @@ -313,6 +330,7 @@ public final class ParcelableCall implements Parcelable { destination.writeInt(mCallerDisplayNamePresentation); destination.writeParcelable(mGatewayInfo, 0); destination.writeParcelable(mAccountHandle, 0); + destination.writeByte((byte) (mIsVideoCallProviderChanged ? 1 : 0)); destination.writeStrongBinder( mVideoCallProvider != null ? mVideoCallProvider.asBinder() : null); destination.writeString(mParentCallId); diff --git a/telecomm/java/android/telecom/ParcelableConference.java b/telecomm/java/android/telecom/ParcelableConference.java index ab82549..e54e79d 100644 --- a/telecomm/java/android/telecom/ParcelableConference.java +++ b/telecomm/java/android/telecom/ParcelableConference.java @@ -34,9 +34,10 @@ public final class ParcelableConference implements Parcelable { private int mState; private int mConnectionCapabilities; private List<String> mConnectionIds; - private long mConnectTimeMillis; + private long mConnectTimeMillis = Conference.CONNECT_TIME_NOT_SPECIFIED; private final IVideoProvider mVideoProvider; private final int mVideoState; + private StatusHints mStatusHints; public ParcelableConference( PhoneAccountHandle phoneAccount, @@ -44,7 +45,9 @@ public final class ParcelableConference implements Parcelable { int connectionCapabilities, List<String> connectionIds, IVideoProvider videoProvider, - int videoState) { + int videoState, + long connectTimeMillis, + StatusHints statusHints) { mPhoneAccount = phoneAccount; mState = state; mConnectionCapabilities = connectionCapabilities; @@ -52,18 +55,8 @@ public final class ParcelableConference implements Parcelable { mConnectTimeMillis = Conference.CONNECT_TIME_NOT_SPECIFIED; mVideoProvider = videoProvider; mVideoState = videoState; - } - - public ParcelableConference( - PhoneAccountHandle phoneAccount, - int state, - int connectionCapabilities, - List<String> connectionIds, - IVideoProvider videoProvider, - int videoState, - long connectTimeMillis) { - this(phoneAccount, state, connectionCapabilities, connectionIds, videoProvider, videoState); mConnectTimeMillis = connectTimeMillis; + mStatusHints = statusHints; } @Override @@ -113,6 +106,10 @@ public final class ParcelableConference implements Parcelable { return mVideoState; } + public StatusHints getStatusHints() { + return mStatusHints; + } + public static final Parcelable.Creator<ParcelableConference> CREATOR = new Parcelable.Creator<ParcelableConference> () { @Override @@ -124,13 +121,14 @@ public final class ParcelableConference implements Parcelable { List<String> connectionIds = new ArrayList<>(2); source.readList(connectionIds, classLoader); long connectTimeMillis = source.readLong(); + StatusHints statusHints = source.readParcelable(classLoader); IVideoProvider videoCallProvider = IVideoProvider.Stub.asInterface(source.readStrongBinder()); int videoState = source.readInt(); return new ParcelableConference(phoneAccount, state, capabilities, connectionIds, - videoCallProvider, videoState); + videoCallProvider, videoState, connectTimeMillis, statusHints); } @Override @@ -156,5 +154,6 @@ public final class ParcelableConference implements Parcelable { destination.writeStrongBinder( mVideoProvider != null ? mVideoProvider.asBinder() : null); destination.writeInt(mVideoState); + destination.writeParcelable(mStatusHints, 0); } } diff --git a/telecomm/java/android/telecom/Phone.java b/telecomm/java/android/telecom/Phone.java index c1c1129..3d9acda 100644 --- a/telecomm/java/android/telecom/Phone.java +++ b/telecomm/java/android/telecom/Phone.java @@ -122,6 +122,11 @@ public final class Phone { final void internalRemoveCall(Call call) { mCallByTelecomCallId.remove(call.internalGetCallId()); mCalls.remove(call); + + InCallService.VideoCall videoCall = call.getVideoCall(); + if (videoCall != null) { + videoCall.unregisterCallback(); + } fireCallRemoved(call); } @@ -167,6 +172,10 @@ public final class Phone { */ final void destroy() { for (Call call : mCalls) { + InCallService.VideoCall videoCall = call.getVideoCall(); + if (videoCall != null) { + videoCall.unregisterCallback(); + } if (call.getState() != Call.STATE_DISCONNECTED) { call.internalSetDisconnected(); } diff --git a/telecomm/java/android/telecom/RemoteConnection.java b/telecomm/java/android/telecom/RemoteConnection.java index 4c423f2..4ecfd50 100644 --- a/telecomm/java/android/telecom/RemoteConnection.java +++ b/telecomm/java/android/telecom/RemoteConnection.java @@ -301,7 +301,7 @@ public final class RemoteConnection { public VideoProvider(IVideoProvider videoProviderBinder) { mVideoProviderBinder = videoProviderBinder; try { - mVideoProviderBinder.setVideoCallback(mVideoCallbackServant.getStub().asBinder()); + mVideoProviderBinder.addVideoCallback(mVideoCallbackServant.getStub().asBinder()); } catch (RemoteException e) { } } diff --git a/telecomm/java/android/telecom/VideoCallImpl.java b/telecomm/java/android/telecom/VideoCallImpl.java index 7bef688..3779d1a 100644 --- a/telecomm/java/android/telecom/VideoCallImpl.java +++ b/telecomm/java/android/telecom/VideoCallImpl.java @@ -166,7 +166,7 @@ public class VideoCallImpl extends VideoCall { mVideoProvider.asBinder().linkToDeath(mDeathRecipient, 0); mBinder = new VideoCallListenerBinder(); - mVideoProvider.setVideoCallback(mBinder); + mVideoProvider.addVideoCallback(mBinder); } /** {@inheritDoc} */ @@ -175,6 +175,15 @@ public class VideoCallImpl extends VideoCall { } /** {@inheritDoc} */ + public void unregisterCallback() { + mCallback = null; + try { + mVideoProvider.removeVideoCallback(mBinder); + } catch (RemoteException e) { + } + } + + /** {@inheritDoc} */ public void setCamera(String cameraId) { try { mVideoProvider.setCamera(cameraId); diff --git a/telecomm/java/com/android/internal/telecom/IVideoProvider.aidl b/telecomm/java/com/android/internal/telecom/IVideoProvider.aidl index e96d9d3..bff3865 100644 --- a/telecomm/java/com/android/internal/telecom/IVideoProvider.aidl +++ b/telecomm/java/com/android/internal/telecom/IVideoProvider.aidl @@ -25,7 +25,9 @@ import android.telecom.VideoProfile; * @hide */ oneway interface IVideoProvider { - void setVideoCallback(IBinder videoCallbackBinder); + void addVideoCallback(IBinder videoCallbackBinder); + + void removeVideoCallback(IBinder videoCallbackBinder); void setCamera(String cameraId); diff --git a/telephony/java/com/android/ims/internal/IImsCallSessionListener.aidl b/telephony/java/com/android/ims/internal/IImsCallSessionListener.aidl index 84d1c545..0443c3e 100644 --- a/telephony/java/com/android/ims/internal/IImsCallSessionListener.aidl +++ b/telephony/java/com/android/ims/internal/IImsCallSessionListener.aidl @@ -115,4 +115,12 @@ interface IImsCallSessionListener { * - {@link com.android.internal.telephony.Phone#TTY_MODE_VCO} */ void callSessionTtyModeReceived(in IImsCallSession session, in int mode); + + /** + * Notifies of a change to the multiparty state for this {@code ImsCallSession}. + * + * @param session The call session. + * @param isMultiParty {@code true} if the session became multiparty, {@code false} otherwise. + */ + void callSessionMultipartyStateChanged(in IImsCallSession session, in boolean isMultiParty); } diff --git a/wifi/java/android/net/wifi/RttManager.java b/wifi/java/android/net/wifi/RttManager.java index b156d0c..d2fb0dd 100644 --- a/wifi/java/android/net/wifi/RttManager.java +++ b/wifi/java/android/net/wifi/RttManager.java @@ -808,7 +808,7 @@ public class RttManager { if (mRttCapabilities == null) { if(getRttCapabilities() == null) { Log.e(TAG, "Can not get RTT capabilities"); - //throw new IllegalStateException("RTT chip is not working"); + throw new IllegalStateException("RTT chip is not working"); } } @@ -866,6 +866,15 @@ public class RttManager { return true; } + /** + * Request to start an RTT ranging + * + * @param params -- RTT request Parameters + * @param listener -- Call back to inform RTT result + * @exception throw IllegalArgumentException when params are illegal + * throw IllegalStateException when RttCapabilities do not exist + */ + public void startRanging(RttParams[] params, RttListener listener) { int index = 0; for(RttParams rttParam : params) { @@ -874,9 +883,9 @@ public class RttManager { } index++; } - validateChannel(); ParcelableRttParams parcelableParams = new ParcelableRttParams(params); + Log.i(TAG, "Send RTT request to RTT Service"); sAsyncChannel.sendMessage(CMD_OP_START_RANGING, 0, putListener(listener), parcelableParams); } @@ -1024,6 +1033,7 @@ public class RttManager { } @Override public void handleMessage(Message msg) { + Log.i(TAG, "RTT manager get message: " + msg.what); switch (msg.what) { case AsyncChannel.CMD_CHANNEL_HALF_CONNECTED: if (msg.arg1 == AsyncChannel.STATUS_SUCCESSFUL) { @@ -1049,10 +1059,10 @@ public class RttManager { Object listener = getListener(msg.arg2); if (listener == null) { - if (DBG) Log.d(TAG, "invalid listener key = " + msg.arg2); + Log.e(TAG, "invalid listener key = " + msg.arg2 ); return; } else { - if (DBG) Log.d(TAG, "listener key = " + msg.arg2); + Log.i(TAG, "listener key = " + msg.arg2); } switch (msg.what) { diff --git a/wifi/java/android/net/wifi/WifiConfiguration.java b/wifi/java/android/net/wifi/WifiConfiguration.java index c6f2991..b731316 100644 --- a/wifi/java/android/net/wifi/WifiConfiguration.java +++ b/wifi/java/android/net/wifi/WifiConfiguration.java @@ -243,6 +243,7 @@ public class WifiConfiguration implements Parcelable { * The band which AP resides on * 0-2G 1-5G * By default, 2G is chosen + * @hide */ public int apBand = 0; @@ -251,6 +252,7 @@ public class WifiConfiguration implements Parcelable { * 2G 1-11 * 5G 36,40,44,48,149,153,157,161,165 * 0 - find a random available channel according to the apBand + * @hide */ public int apChannel = 0; @@ -953,7 +955,7 @@ public class WifiConfiguration implements Parcelable { if (!TextUtils.isEmpty(FQDN)) { /* this is passpoint configuration; it must not have an SSID */ if (!TextUtils.isEmpty(SSID)) { - return "no SSID"; + return "SSID not expected for Passpoint: '" + SSID + "'"; } /* this is passpoint configuration; it must have a providerFriendlyName */ if (TextUtils.isEmpty(providerFriendlyName)) { diff --git a/wifi/java/android/net/wifi/WifiEnterpriseConfig.java b/wifi/java/android/net/wifi/WifiEnterpriseConfig.java index 6917971..3525ec2 100644 --- a/wifi/java/android/net/wifi/WifiEnterpriseConfig.java +++ b/wifi/java/android/net/wifi/WifiEnterpriseConfig.java @@ -56,6 +56,8 @@ public class WifiEnterpriseConfig implements Parcelable { /** @hide */ public static final String ALTSUBJECT_MATCH_KEY = "altsubject_match"; /** @hide */ + public static final String DOM_SUFFIX_MATCH_KEY = "domain_suffix_match"; + /** @hide */ public static final String OPP_KEY_CACHING = "proactive_key_caching"; /** * String representing the keystore OpenSSL ENGINE's ID. @@ -577,6 +579,36 @@ public class WifiEnterpriseConfig implements Parcelable { } /** + * Set the domain_suffix_match directive on wpa_supplicant. This is the parameter to use + * for Hotspot 2.0 defined matching of AAA server certs per WFA HS2.0 spec, section 7.3.3.2, + * second paragraph. + * + * From wpa_supplicant documentation: + * Constraint for server domain name. If set, this FQDN is used as a suffix match requirement + * for the AAAserver certificate in SubjectAltName dNSName element(s). If a matching dNSName is + * found, this constraint is met. If no dNSName values are present, this constraint is matched + * against SubjectName CN using same suffix match comparison. + * Suffix match here means that the host/domain name is compared one label at a time starting + * from the top-level domain and all the labels in domain_suffix_match shall be included in the + * certificate. The certificate may include additional sub-level labels in addition to the + * required labels. + * For example, domain_suffix_match=example.com would match test.example.com but would not + * match test-example.com. + * @param domain The domain value + */ + public void setDomainSuffixMatch(String domain) { + setFieldValue(DOM_SUFFIX_MATCH_KEY, domain); + } + + /** + * Get the domain_suffix_match value. See setDomSuffixMatch. + * @return The domain value. + */ + public String getDomainSubjectMatch() { + return getFieldValue(DOM_SUFFIX_MATCH_KEY, ""); + } + + /** * Set realm for passpoint credential * @param realm the realm */ |