diff options
author | Etan Cohen <etancohen@google.com> | 2015-04-25 00:49:40 +0000 |
---|---|---|
committer | Android (Google) Code Review <android-gerrit@google.com> | 2015-04-25 00:51:47 +0000 |
commit | cd895cdf4dd98b4271e24742a6a46be70cda6382 (patch) | |
tree | abe33abdc2107c5888acafde50bb23040c65f680 | |
parent | 998ee16570e541e74e90eac39f468e6d8d1cd6f8 (diff) | |
parent | 1418054108e3811db80e28496b335514b51b10f4 (diff) | |
download | frameworks_base-cd895cdf4dd98b4271e24742a6a46be70cda6382.zip frameworks_base-cd895cdf4dd98b4271e24742a6a46be70cda6382.tar.gz frameworks_base-cd895cdf4dd98b4271e24742a6a46be70cda6382.tar.bz2 |
Merge changes from topic 'mwd-merge-042415'
* changes:
Rename removeVideoCallListener to unregisterCallback
Bluetooth document fix: remove reference from open API to hidden entities
Fix build due to merge of 7595842 and renaming due to 8eb87f0
Merge commit '052a0da' into merge2
Merge commit 'db1dbb8' into merge2
Merge commit '7e5e791' into merge2
Merge commit '170102d' into merge2
Merge commit '4cb5d80' into merge2
Merge commit '83cda00' into merge2
Merge commit 'c91bc62' into merge2
Merge commit 'cffc360' into merge2
Merge commit '7f61051' into merge2
Merge commit '167c3a7' into merge2
Merge commit '4467b98' into merge2
Merge commit '25a217c' into merge2
Merge commit '04b18ec' into merge2
Merge commit '7595842' into merge2
Merge commit '2bbd2b6' into merge2
Merge commit '4890351' into merge2
Merge commit 'cd405fe' into merge2
Merge commit '6ddbb5e' into merge2
Merge commit 'de93575' into merge2
Merge commit '9561e74' into merge2
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 */ |